"Client copy" with PL/SQL [message #633213] |
Thu, 12 February 2015 06:50 |
|
wurmi
Messages: 4 Registered: February 2015 Location: Germany
|
Junior Member |
|
|
Hello everybody,
maybe you can help with weak cursors. I have searched through PL/SQL tutorials but have not found a example to my issue, so I am not sure if the way I want to go is possible at all.
Im my schema, there are about 50 tables, which all have a composite primary key with first attribute MANDT (CHAR 1). I have adapted this concept from SAP.
So there are e.g. 2 tables
CREATE TABLE employees(
MANDT CHAR(1) NOT NULL,
EMPLOYEE VARCHAR2(10) NOT NULL,
NAME VARCHAR2(50) NOT NULL),
CONSTRAINT employee_pk PRIMARY KEY (MANDT, EMPLOYEE));
CREATE TABLE dept(
MANDT CHAR(1) NOT NULL,
DEPT VARCHAR2(10) NOT NULL,
NAME VARCHAR2(50) NOT NULL),
CONSTRAINT dept_pk PRIMARY KEY (MANDT, DEPT));
and there is one table which contains the table names:
CREATE TABLE MYTABLES(
TABLENAME VARCHAR2(20) NOT NULL,
CONSTRAINT mytables_pk PRIMARY KEY (TABLENAME));
I need a procedure in PL/SQL which can copy the entries from one client ("MANDT") to another client.
E.g. in table employees there are the following entries:
A;JOHN;John doe
A;JANET;Janet doe
A;SMITH;Mr. Smith
B;JIM;Jim Beam
After the copy from client A to client B, the entries should be like that:
A;JOHN;John doe
A;JANET;Janet doe
A;SMITH;Mr. Smith
B;JOHN;John doe
B;JANET;Janet doe
B;SMITH;Mr. Smith
What I was doing is to loop at all entries in the table mytables and do
--DELETE the existing entries in target client
v_del = 'DELETE FROM ' || crs_tables.TABLENAME || ' WHERE MANDT =: target'
execute immediate v_del USING 'A'.
--Loop at the source entries
v_sel = 'SELECT FROM ' || crs_tables.TABLENAME || ' WHERE MANDT =: source'
open ref cursor
Here is my problem: How can I get each line of the legacy cursor into a line variable, change the MANDT column to 'B' and then INSERT into the database? I want to avoid to write explicitely the same step for each of the 50 tables.
Is there an efficient way to do this?
|
|
|
|
|
|
Re: "Client copy" with PL/SQL [message #633217 is a reply to message #633215] |
Thu, 12 February 2015 07:17 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
@OP, what is the purpose of having table names in a separate table? And if you really want to loop through all tables dynamically, then Oracle has the metadata, *_TABLES view. But I don't know the purpose of all this.
Another thing, if you want to do DELETE and INSERT, I would suggest MERGE statement.
|
|
|
|
Re: "Client copy" with PL/SQL [message #633219 is a reply to message #633217] |
Thu, 12 February 2015 07:28 |
|
wurmi
Messages: 4 Registered: February 2015 Location: Germany
|
Junior Member |
|
|
Lalit Kumar B wrote on Thu, 12 February 2015 07:17@OP, what is the purpose of having table names in a separate table?
Not all tables in user_tables are client dependent, i.e. some master data do not have the MANDT Attribute in their key. So I decided to put all the relevant tables in a control table. Also the deleting and inserting needs to be done in a defined order because of foreign key constraints.
How do I use user_tab_cols view to fill the insert Statement by cookiemonster? I am new to PL/SQL and always tend to concatenate SQL-Strings before executing; however I know need to get over this...
Right now, I do not have Access to a database and can not try things out.
[Updated on: Thu, 12 February 2015 07:28] Report message to a moderator
|
|
|
Re: "Client copy" with PL/SQL [message #633220 is a reply to message #633219] |
Thu, 12 February 2015 07:33 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
I am not sure of what you are trying to imement, so I will only answer about getting column names for the table names that you have stored in a separate table.
You can join MYTABLES with the view I mentioned, join on table_name and select the column names from the view to get the column names for each table.
|
|
|
|
Re: "Client copy" with PL/SQL [message #633223 is a reply to message #633219] |
Thu, 12 February 2015 08:18 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
wurmi wrote on Thu, 12 February 2015 13:28
Not all tables in user_tables are client dependent, i.e. some master data do not have the MANDT Attribute in their key. So I decided to put all the relevant tables in a control table.
If all the relevant tables have the mandt column and the non-relevant tables don't then you could just query user_tab_columns for the list of tables with a column called mandt.
wurmi wrote on Thu, 12 February 2015 13:28
How do I use user_tab_cols view to fill the insert Statement by cookiemonster? I am new to PL/SQL and always tend to concatenate SQL-Strings before executing; however I know need to get over this...
Loop over list of columns, append each one to a string, adding a comma seperater between each one.
Concatenate string with rest of statement.
|
|
|
Re: "Client copy" with PL/SQL [message #633224 is a reply to message #633216] |
Thu, 12 February 2015 08:22 |
John Watson
Messages: 8931 Registered: January 2010 Location: Global Village
|
Senior Member |
|
|
The CREATE TABLE statments you provided do not run. Check your use of brackets. In future, please test code before you post it.
You are making this very complicated. To copy rows with a different value for MANDT, all you need is something like
insert into employees select 'B',employee,name from employees where mandt='A';
|
|
|
|
Re: "Client copy" with PL/SQL [message #633226 is a reply to message #633223] |
Thu, 12 February 2015 08:24 |
Lalit Kumar B
Messages: 3174 Registered: May 2013 Location: World Wide on the Web
|
Senior Member |
|
|
@CM,
I didn't understand, why comma separated column names? OP has a list of table names, he needs column names for each table, so I suggested the join of that table with the user_tab_cols view. The same column name could be used in OP's dynamic query. Am I missing something in your suggestion?
|
|
|
|
|
Re: "Client copy" with PL/SQL [message #633229 is a reply to message #633225] |
Thu, 12 February 2015 08:43 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
BlackSwan wrote on Thu, 12 February 2015 14:24>Is there an efficient way to do this?
use Oracle provided utilities; expdp & impdp otherwise new tables are missing column constraints that old tables have.
You haven't read the question properly
|
|
|
Re: "Client copy" with PL/SQL [message #633230 is a reply to message #633226] |
Thu, 12 February 2015 08:46 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
Lalit Kumar B wrote on Thu, 12 February 2015 14:24@CM,
I didn't understand, why comma separated column names?
Because a select statement where the column names aren't comma separated is invalid. I'm not suggesting anything clever here, just pointing out the basics of generating a select statement using user_tab_columns.
|
|
|
Re: "Client copy" with PL/SQL [message #633231 is a reply to message #633224] |
Thu, 12 February 2015 08:49 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
John Watson wrote on Thu, 12 February 2015 14:22The CREATE TABLE statments you provided do not run. Check your use of brackets. In future, please test code before you post it.
You are making this very complicated. To copy rows with a different value for MANDT, all you need is something like
insert into employees select 'B',employee,name from employees where mandt='A';
That is just the static version of what I already suggested.
To be honest, assuming new tables can't be created on the fly, it's the better approach and I should have pointed it out before.
Just create one procedure with a set of hard-coded delete and insert statements. If a new table is added then modify the procedure to include it.
If tables can be created on the lfy then that's a seperate design issue that really should be fixed before it causes significant problems.
|
|
|
Re: "Client copy" with PL/SQL [message #633232 is a reply to message #633231] |
Thu, 12 February 2015 08:51 |
cookiemonster
Messages: 13920 Registered: September 2008 Location: Rainy Manchester
|
Senior Member |
|
|
I also have to suspect, as Roachcoach pointed out, that if you're copying existing data in this manner then there is probably a better solution that doesn't invlove copying tons of data.
|
|
|
Re: "Client copy" with PL/SQL [message #633313 is a reply to message #633213] |
Sun, 15 February 2015 09:29 |
|
wurmi
Messages: 4 Registered: February 2015 Location: Germany
|
Junior Member |
|
|
Hallo everybody,
thank your for your tips and hints, I have included them into my code.
The database where I will be using my procedure is just a personal test database where it should be possible to create quick snapshots and switch between them. No tons of data and security issues. Since I worked many years with SAP, the leading MANDT column and the "Client copy" is something very common to me, although it may seem odd to somebody who sees that for the first time.
After fiddling around, here is something that works. The commit statements however are now on statement level, will be corrected later. Feel free to comment.
create or replace procedure prc_test as
cursor cur_DELETE is
select UPPER(TABELLENNAME) as TABELLE
from TBLMANDTSchema
where MITMANDT='X'
order by RHFLG desc;
cursor cur_TABLES is
select UPPER(TABELLENNAME) AS TABELLE
from TBLMANDTSCHEMA
where MITMANDT='X'
order by RHFLG asc;
wa_col user_tab_cols%ROWTYPE;
wa_table cur_DELETE%ROWTYPE;
v_delete varchar2(255);
v_select varchar2(255);
v_cols varchar2(255);
v_qmandt char(1);
v_zmandt char(1);
BEGIN
v_qmandt := '0'; --source client
v_zmandt := '3'; --target client
dbms_output.put_line('Start deleting:');
/* DELETE ENTRIES IN TARGET CLIENT */
for wa_table in cur_DELETE
loop
v_delete := 'DELETE FROM ' || wa_table.TABELLE || ' WHERE MANDT= :m';
dbms_output.put_line( v_delete );
execute immediate v_delete using v_zmandt;
commit;
end loop;
dbms_output.put_line('Start copying:');
for wa_table in cur_TABLES
loop
/* CONCATENATE COLUMNS OTHER THAN 'MANDT' */
declare
cursor cur_TABELLEN_SP is
SELECT * FROM USER_TAB_COLS WHERE TABLE_NAME = wa_table.TABELLE
AND COLUMN_NAME <> 'MANDT'
ORDER BY COLUMN_ID;
begin
v_cols := '';
for wa_col in cur_TABELLEN_sp
loop
--dbms_output.put_line( wa_col.column_name );
v_cols := v_cols || wa_col.column_name || ', ';
end loop;
end;
v_cols := substr(v_cols, 0, LENGTH(v_cols)-2);
dbms_output.put_line( 'Table ' || wa_table.TABELLE || ' has columns: ' || v_cols);
v_SELECT := 'INSERT INTO ' || wa_table.TABELLE || ' SELECT :t , ' || v_cols || ' FROM ' || wa_table.TABELLE || ' WHERE MANDT = :s';
execute immediate v_select using v_zmandt, v_qmandt;
commit;
end loop;
end prc_test;
|
|
|