ORACLE SQL Execute Multiple DML Statements Concurrently within single Stored Procedure - oracle

I have written a Stored Procedure which has 10 DML statements in series where each DML statement takes around 3 minutes for execution. The total Stored Procedure runs for about 29 minutes in production (Each DML dumps millions of record).
I would need 1st two DML statements alone to run in series and the remaining 8 can run in parallel, since they have no dependency.
Need advice to achieve this without using dbms_job or dbms_scheduler
begin
insert all into table1 values ()
insert all into table2 values ()
select ...;
insert into table3 select ... from table1 join table2...;
insert into table4 select ... from table2 join tableA...;
insert into table5 select ... from table1 join tableB...;
insert into table6 select ... from table1 join tableC...;
insert into table7 select ... from table1 join tableD...;
insert into table8 select ... from table1 join tableE...;
insert into table9 select ... from table1 join tableF...;
insert into table10 select ... from table1 join tableG...;
end;

Related

Cursor with multiple queries in oracle not compiling

I have created a cursor that has two queries joined with inner join, but query is not compiling their is error at the end of first query but the same query is getting executed without cursor.
cursor data is
select * from
select rid,id, order from table1
inner join
select pid, name, order from table2
on table1.order = table2.order
original query is much bigger and complicated but end result would be this.
Their are compilation errors at the end of first query and those are generic nature, I guess may be syntax for creating a two joined queries is wrong (this is a wild guess though)
Error:
SQL statement ignored //at select word of first query
Missing right parenthesis //at the last word of first query
Example based on Scott's schema:
SELECT should contain column aliases if columns returned by those inline views share the same name; otherwise, you won't know which one you're using
inline views should have their own aliases; basically, that's always a good idea - prefix columns with table aliases, otherwise you'll soon forget which column belongs to which table
SQL> declare
2 cursor data is
3 select a.empno a_empno, b.ename b_ename
4 from (select empno, ename, deptno from emp) a
5 inner join
6 (select empno, ename, deptno from emp) b
7 on a.deptno = b.deptno
8 where rownum < 5;
9 begin
10 for data_r in data loop
11 dbms_output.put_line(data_r.b_ename);
12 end loop;
13 end;
14 /
SMITH
JONES
SCOTT
ADAMS
PL/SQL procedure successfully completed.
SQL>
You have to put your subqueries in parenthesis and add aliases for the subqueries:
cursor data is
select * from
(select rid,id, order from table1) table1
inner join
(select pid, name, order from table2) table2
on table1.order = table2.order
Here is another answer for you, with just small differences and with an example:
CREATE OR REPLACE PROCEDURE p_test(n_test in number)
AS
CURSOR data
IS
SELECT *
FROM
(SELECT rid
, id
, "order" or1
FROM table1) tab1
INNER JOIN
(SELECT pid
, name
, "order" or1
FROM table2 ) tab2
ON tab1.or1 = tab2.or1;
BEGIN
FOR data_i IN data LOOP
DBMS_OUTPUT.PUT_LINE(data_i.rid);
END LOOP;
END p_test;
Here is the DEMO

INSERT-SELECT (Oracle PL/SQL) - Performance Issue

I have too many SELECT statements toghether with only one INSERT (maybe hundreds of them) And the system is giving a bad performance.
I will explain in general words what is happening and what I'm searching for:
Considering the following two pseudo-codes in Oracle PL/SQL, which of them would give the best performance?
Option A:
INSERT INTO MyTable
WITH Fields AS (
SELECT Field1, Field2, ..., FieldN FROM TableA JOIN TableW .... WHERE <condition1>
UNION ALL
SELECT Field1, Field2, ..., FieldN FROM TableB JOIN TableX .... WHERE <condition2>
UNION ALL
SELECT Field1, Field2, ..., FieldN FROM TableC JOIN TableB .... WHERE <condition3>
....
UNION ALL
....
SELECT Field1, Field2, ..., FieldN FROM TableZZZ JOIN TableB .... WHERE <conditionN>
Option B:
BEGIN
INSERT INTO MyTable SELECT Field1, Field2, ..., FieldN FROM TableA JOIN TableZ .... WHERE <condition1>
INSERT INTO MyTable SELECT Field1, Field2, ..., FieldN FROM TableB JOIN TableW .... WHERE <condition2>
INSERT INTO MyTable SELECT Field1, Field2, ..., FieldN FROM TableC JOIN TableH .... WHERE <condition3>
...
INSERT INTO MyTable SELECT Field1, Field2, ..., FieldN FROM TableZZZZ JOIN TableX .... WHERE <conditionN>
END
I didn't put the real table names, but I would like to know: if I change the current option A to option B, would it present me a better performance? I mean, is it a good idea to replace UNION ALL with many INSERT statements in this case?
Context Switches and Performance
Almost every program PL/SQL developers write includes both PL/SQL and SQL statements. PL/SQL statements are run by the PL/SQL statement executor;
SQL statements are run by the SQL statement executor. When the PL/SQL runtime engine encounters a SQL statement, it stops and passes the SQL statement over to the SQL engine. The SQL engine executes the SQL statement and returns information back to the PL/SQL engine (see Figure 1). This transfer of control is called a context switch, and each one of these switches incurs overhead that slows down the overall performance of your programs.
so, use this third way:
create view MyView as select Field1, Field2, ..., FieldN from TableA join TableB .... where <condition1>
declare
p_array_size pls_integer := 100;
type array is table of MyView%rowtype;
l_data array;
cursor c is select * from MyView;
begin
open c;
loop
fetch c bulk collect into l_data limit p_array_size;
forall i in 1..l_data.count
insert into MyTable values l_data(i);
exit when c%notfound;
end loop;
close c;
end;
Except your queries are very peculiar in terms of memory on your database server, option B is not going to increase the performance of the big query.
To ensure the above is true, try ask your DBA to check what happens in your databsae sever SGA at the time you perform the query. If a jam in the memory occurs, then it is worth trying to implement option B.
When I say "memory jams", I mean whole SGA memory is filled, making swap necessary on the server. If you do the inserts in a sequence, then SGA can be reused between the inserts.

Hive :Insert the records that are not present

I need to insert records into a table t1 from another table t2 such that insert only the records that are not in t2.
But when i use this query
insert into table t1 select * from t2 where id not in (select id from t1);
But I get error as
Correlating expression cannot contain qualified column reference.
Can anybody suggest me a query to do this.
t2.id
Yet another ridiculous hive limitation
insert into table t1 select * from t2 where t2.id not in (select id from t1);
You can also use below command :-
insert into table t1 select t2.* from t2 left join t1 on t2.id=t1.id where t1.id is NULL;

subquery inside INSERT statement

I just recently found out that subqueries are not allowed in INSERT statements that are inside stored procedures. This is my script:
begin
execute immediate 'truncate table itcustadm.GL_DTPJ_TEST2';
insert into GL_DTPJ_TEST2
(rule_no,
posted_by_user_id,
transaction_id,
transaction_sr_no,
dr_amount,
cr_amount,
tran_crncy_code,
bkdt_tran_flg,
bank_desc
)
select
tq.rule_no,
tq.posted_by_user_id,
tq.transaction_id,
tq.transaction_sr_no,
tq.dr_amount,
tq.cr_amount,
tq.tran_crncy_code,
tq.bkdt_tran_flg,
(select ent.bank_desc from crmuser.end ent where ent.bank_id = gam.bank_id);
But since the (select ent.bank_desc from crmuser.end ent where ent.bank_id = gam.bank_id) at the bottom of the SELECT statement is not allowed by Oracle, what's the best way to accomplish this?
I actually have this code right before the INSERT statement, but I don't know how to exactly use it:
get_bank_desc := '(select ent.bank_desc from crmuser.end ent ' ||
'where ent.bank_id = gam.bank_id)';
I am not sure what you are exactly trying for, but below code may be useful for you, you can achieve inserting a SubQuery output into a table using below query sample, but make sure output of the SubQuery is a single row o/p, so that you can escape from "ORA-01427: single-row SubQuery returns more than one row" ERROR.
insert into test_ins1
values(1,(SELECT COL2 FROM TEST_INS WHERE COL1=1 ));
Even then you can use rownum in where condition and take the single value.
Please let me know in case of any doubts
declare
bank_desc_temp bank_desk_type; /* the type defined in crmuser.ent for bank_desc*/
begin
select ent.bank_desc into bank_desc_temp from crmuser.end ent where ent.bank_id = gam.bank_id;
execute immediate 'truncate table itcustadm.GL_DTPJ_TEST2';
insert into GL_DTPJ_TEST2
(rule_no,
posted_by_user_id,
transaction_id,
transaction_sr_no,
dr_amount,
cr_amount,
tran_crncy_code,
bkdt_tran_flg,
bank_desc
)
select
tq.rule_no,
tq.posted_by_user_id,
tq.transaction_id,
tq.transaction_sr_no,
tq.dr_amount,
tq.cr_amount,
tq.tran_crncy_code,
tq.bkdt_tran_flg,
bank_desc_temp;
end;
When you say "not allowed" what do you mean? Did you get an error?
I ask, because subqueries are definitely allowed inside an insert as select statement, providing you have the syntax correct (and the subquery returns at most one row), e.g.:
create table test_tab (col1 number, col2 varchar2(10));
begin
insert into test_tab
select 1,
(select 'Yes' from dual d2 where d.dummy = d2.dummy)
from dual d;
commit;
end;
/
select * from test_tab;
COL1 COL2
---------- ----------
1 Yes
There are some syntax issues with the code you provided - where is the from clause, and where are the tq and gam aliases defined?
There are two syntax you can use in your insert statement:
(I)
INSERT INTO table_name( column1, column2....columnN)
VALUES ( value1, value2....valueN);
(II)
INSERT INTO table (column1, column2, ... )
SELECT expression1, expression2, ...
FROM source_table(s)
WHERE conditions;
In your example, you should choose the second approach:
insert into GL_DTPJ_TEST2 (rule_no,
posted_by_user_id,
transaction_id,
transaction_sr_no,
dr_amount,
cr_amount,
tran_crncy_code,
bkdt_tran_flg,
bank_desc
)
select tq.rule_no,
tq.posted_by_user_id,
tq.transaction_id,
tq.transaction_sr_no,
tq.dr_amount,
tq.cr_amount,
tq.tran_crncy_code,
tq.bkdt_tran_flg,
ent.bank_desc
from crmuser.gam
join crmuser.end ent
on ent.bank_id = gam.bank_id
;
basically, if you want to add records using an insert statement, you should use a full select statement first. Here is how I would do it:
(1)
select *
from table1;
(2)
select column1
,column2
,column3
from table1;
(3)
select t1.column1
,t1.column2
,t1.column3
,t2.column4
,t2.column5
from table1 t1
join table2 t2
on t2.id = t1.id
;
(4)
insert into table3 (col1
,col2
,col3
,col4
,col5)
select t1.column1
,t1.column2
,t1.column3
,t2.column4
,t2.column5
from table1 t1
join table2 t2
on t2.id = t1.id
;

Insert into select query with cursor value

I want to write a SQK script with insert query in Oracle where one of the value will be fetched from cursor and rest all will be retrieved from table.
For example, consider Employee table:
Emp_No | Emp_Name
1 | AAA
...........
I am reading the table into a cursor.
Cursor c1 is select emp_no, emp_name from employee;
I am iterating the cursor and adding to a table along with information from another table.
for empCur in c1
loop
insert into employee_info(emp_no, emp_name, address, age, ... ) values (empCur.emp_no, empCur.emp_name, select t.address, t.age, ... from employee_temp_table t where t.emp_no=empCur.emp_no)
end loop;
Is my script valid? If not is there any other way to achieve it? Since few values are in cursor and few are in another table I am not sure how to handle this.
Your script isn't correct because this
select t.address, t.age, ... from employee_temp_table t where t.emp_no=empCur.emp_no
is not a valid expression. You may use a scalar subquery (one-row, one-column subquery) only, like this:
insert into t1(col1, col2, col3) values (1, (select col1 from t2), (select col2 from t2));
Or you may try insert from select:
for empCur in c1 loop
insert into employee_info(emp_no, emp_name, address, age, ... )
select empCur.emp_no, empCur.emp_name, t.address, t.age, ... from employee_temp_table t where t.emp_no=empCur.emp_no;
end loop;
If you want to use the cursor, why not just join the tables inside the cursor?
for empCur in ( select e.emp_no, e.emp_name, t.address, t.age ...
from employee e join employee_temp_table t on ( t.emp_no = e.emp_no )
) loop
insert into employee_info(...) values ( empCur.emp_no, ...);
end loop;
Or with a sql insert: (if you can choose sql over pl/sql - T Kyte says do it)
insert into employee_info
select e.emp_no, e.emp_name, t.address, t.age ...
from employee e join employee_temp_table t on ( t.emp_no = e.emp_no );

Resources