Bulk insert using FORALL in Oracle - oracle

I am currently using the following code to do a bulk insert of 50 million rows:
declare cnt number;
BEGIN
select max(run_ver_issue_id) into cnt from "ABHINAV"."MV_RUN_VER_ISSUE";
FOR x IN 1 .. 50000000 LOOP
INSERT INTO "ABHINAV"."MV_RUN_VER_ISSUE" NOLOGGING ("RUN_VER_ISSUE_ID","CUST_ISSUE_ID","TITLE","ORIGINAL_ISSUE_ID","SOURCE_FILE_LINE","DISPLAY_TEXT","RUN_VER_ID","SANDBOX_SRC_FILE_ID","ACCOUNT_ID","ISSUE_STATE","CURRENT_SEVERITY","INSERT_TS","MODIFIED_TS","CWE_ID","TEMPLATE_FILE_ID","TEMPLATE_FILE_LINE","CURRENT_EXPLOIT_LEVEL","CNT","SOURCE_FUNCTION_PROTOTYPE","SOURCE_RELATIVE_LOCATION","SOURCE_SCOPE","PROCEDURE_NAME","PROCEDURE_HASH","PROTOTYPE_HASH","STATEMENT_HASH","STATEMENT_HASH_COUNT","STATEMENT_HASH_ORDINAL","SUBMODULE_PATH") VALUES (x+cnt,2,..);
END LOOP;
END;
It takes almost 6 hours it to finish. The table does have an index on RUN_VER_ISSUE_ID, but still doesn't help. I tried using FORALL, getting an error PLS-00430: FORALL iteration variable X is not allowed in this context for the below code:
declare cnt number;
BEGIN
select max(run_ver_issue_id) into cnt from "ABHINAV"."MV_RUN_VER_ISSUE";
FORALL x IN 1 .. 5
INSERT INTO "ABHINAV"."MV_RUN_VER_ISSUE" NOLOGGING ("RUN_VER_ISSUE_ID","CUST_ISSUE_ID","TITLE","ORIGINAL_ISSUE_ID","SOURCE_FILE_LINE","DISPLAY_TEXT","RUN_VER_ID","SANDBOX_SRC_FILE_ID","ACCOUNT_ID","ISSUE_STATE","CURRENT_SEVERITY","INSERT_TS","MODIFIED_TS","CWE_ID","TEMPLATE_FILE_ID","TEMPLATE_FILE_LINE","CURRENT_EXPLOIT_LEVEL","CNT","SOURCE_FUNCTION_PROTOTYPE","SOURCE_RELATIVE_LOCATION","SOURCE_SCOPE","PROCEDURE_NAME","PROCEDURE_HASH","PROTOTYPE_HASH","STATEMENT_HASH","STATEMENT_HASH_COUNT","STATEMENT_HASH_ORDINAL","SUBMODULE_PATH") VALUES (x+cnt,2,.....);
END;
I would request you to please provide your suggestions and comments as to how I can speed this up.

you may use this:
declare
p_array_size number := 100000;
type array is table of number;
l_data ARRAY;
cursor c is select rownum seq_no from dual connect by rownum <= p_array_size;
cnt number;
begin
open c;
loop
select max(RUN_VER_ISSUE_ID) into cnt from "ABHINAV"."MV_RUN_VER_ISSUE";
fetch c bulk collect into l_data limit p_array_size;
forall x IN 1 .. l_data.count
insert into "ABHINAV"."MV_RUN_VER_ISSUE"("RUN_VER_ISSUE_ID","CUST_ISSUE_ID","TITLE","ORIGINAL_ISSUE_ID","SOURCE_FILE_LINE","DISPLAY_TEXT","RUN_VER_ID","SANDBOX_SRC_FILE_ID","ACCOUNT_ID","ISSUE_STATE","CURRENT_SEVERITY","INSERT_TS","MODIFIED_TS","CWE_ID","TEMPLATE_FILE_ID","TEMPLATE_FILE_LINE","CURRENT_EXPLOIT_LEVEL","CNT","SOURCE_FUNCTION_PROTOTYPE","SOURCE_RELATIVE_LOCATION","SOURCE_SCOPE","PROCEDURE_NAME","PROCEDURE_HASH","PROTOTYPE_HASH","STATEMENT_HASH","STATEMENT_HASH_COUNT","STATEMENT_HASH_ORDINAL","SUBMODULE_PATH")
values(l_data(x)+cnt,2,'0pJDFy1viDnN2Ku66XPl458gKakF4xz4pTawwoOZYCt0yR2YOw7tH1Mk3oKQ7ynuyasbBjBXr1teBbBdmIsJReIM3kbzWY7H4c6CVgVaw',NULL,230969,'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',74228,2,6120,8096,581270,'26-Sep-12 01:30:00','21-Feb-00 03:52:00',7531,1,NULL,5203,12726,'NAxr4jgRDRnDJiNKp10sfdntA8MKBU0xwWEInpm4yOTjvj5aRHt4fcNujL777cw74AuLEeEskCgzbkZNk2fcaTpBmYl8GtrUsB7KH5Wtfb4Elo8tfpRD7Eh7CjjkTdke7opjX5IBBEDSlxyinbcSLrtK7FuOBXDWM0tMGuq86VlZc27obCFBJyFSGi5FFgAA0PWETUoDR7HerxaisVUzmWuAb1HTKHgdTucNFzvtsxcCXKBwlpE3I7S8G2rhEGs2KOajFOoiB7ZbTPOFSNh7qUEY83GowgJo2lDChWr5tCtQqeJGUyrA2e8kXQ3Oh8Ov28C6muKtSbQFLFrJ0WlQYnDBvXqrHes0wT8rkHMEedJ1NIrf2HBBbI06p2qlO7RCr878gngE3bPiocJAvNHJfnkwnDMu06wda3ZkMmXBL1HTfdPyWfcL44OHzPsQdD4yr6HiM8vP7bzzxXNMBWDuDim8oeAc6o1jByEzgzyztvX6mas4UxAXG4Hm8iWodaoYwUixaFw4vr8qpp7jp8HfYbgC7J6pH4PQKV8krjvGdW3o33tHHBFS6Ytxobi31iSIcSZ2WQcfMzddLi61OmPB3zdKRABt57hj1wbIoQxHUsbsmtHRLZ3fT1V37RLQXfu3GzgjuPLYWxVdQRM7T4v5rhecY7c53ilFIr6KIfeIZ0DY5SGXLWqLoYfN7ZrHHEAONrId0GMeRO2Y0j4uF8j4RXJUpk81wUlFgnlGFkCSKwnXLK7aqYMPri4w0Bp0GixZ7E1JHWOlWDM40VXw5jBz7KnkClba6IaDJNgT8UeUDRHNhNVDiXIWSHLJAUzQqGN5RmG7X6ttpRgQPFpBPXX3UsA758WWSB7d4cNAniSp2jHMhSIl2kRkEnXkm8yuk0B08tDIIEZvDj6zvSsLqDuCmUwpUPcYdsofagnP8WIFoH1fKe4AbbzgUXzTCPgMjKkRvBKoXUgnpWtuNCoz2cosaxDDSOUEuBgX58UltaybzjqS1jMs3F3X3Ewjm2M0wWTeLjuXc3WLjF7OBQAvdDxLUQDRIGDFeeadqbe1gdC7ONr3gZY7w3mYwTJVlCaA0P4qRxhDUDItZNgLEpx4unTsO5Te51PD3YeicmqHlJbxknhjYpciOhfWYrmYGvCCl0xyga0hZ74EDiL1iLQjr1ADRa40SmUh1ufvfbZzcr5OpkttKmeeA75LjDIi58WvajJk0o1bKTgos7OTmhs5LT3cMZ3XJV4An4xtoCNGK4Ktreh6rXTnmHRCQ3HP2kfOTykNT2T8b6vS8rtnsqaLy862mTDBYKnqichIMvyN8fhEaQX0eP5iAs7jn2SrEybNAVOpYzaz6bRFVk1POPaHlkRysYOxGs2r8qumcpSs8ylD3YN2nPCc6OVpBCRw2YT1wozwOOA03r8hDNNz3ZhrNPY6EoW28mOApChU2QHcV63L4S5RiKJYOpAAOeApF5xGOuYnT8Lc4YUHVuwpNSZmxclNL6dzA3MJtCl88J3sZWcuigBgWiDjLUgeVnObW55nj7bYWkZB6UqmBCNNaWaIVkchCMtHNnvHnnoonLuBQTpnHdWy0kXUwY2o3Bd5jnDOQgEMVkiWgoOhRVMbt0cRvxQwSMYkkMyarg1OuYxAGhtY7Orsu1YEhs3MITDhzm4NDDEusaIXdDSaNl4u2ScTYKIsYchLBYo7fa2pvx4oUuaOHAi2oNPRR05zP5pqycSsDpnkEz6YIYBQiZaRgVRp407t83',48913,'7JKWzvKJ4KMb2gz3geo18sMbpkVZNTrYPCvIGjPeO4X5l6KkgYEdfNnGOJFgoeiRbMnLhZ8ahfiNr1VFFRMMIZsp12FAgU0kYTsVRU0ElqlMSs4PCYYqQw2wvqNMnkir8Bm0zYynnDEFIV6h1Dwg42aIFi7ZykkRXj6vQBDTFnYKFjhmrzsnXMLwXjF6Mhf0FMwiuZmbYPacX6KncUeHlUj3oWp6vOxtx5egjBQX1nMH5MZuDG4DYNUFPAPqYxIOWWLiTXDn8qCGcDjwKUWtyBfBkAVjknjxWGtP8ReaRY5yjLKdjWEdhZut1lbGChE8ZbzHSoDqQeyOskrl2ayI6u6ilUZ8kuPLPB60NeE2gOLUGtLUw2L3CPOC7wwMd1SloFV0BLP5LypjWGXHejeR1tK3DRoFyfewWqMCk5wloIn2bgSiam5LiFgRWOZJDQ0METm8JS0geMjkYZlNO3SY8A7U73lrFIAfeoyjy1dtQCxg6BnlhLU5SQZpitqFozzg0QKFpupdKs7zeC3HpbnUZNQIhI0gspIUOzvUgBNyDCh6aHnDrXfrVK38rMPvrdvcFdQFlVvzbjrv4h7mJjfGBarBGvGRplvRT4Iw663YYxeDq5f2DK5NETBEOTnC8wFzmBArRTDn6UPDl2fRvvalugyQGPNxjPBBPAXQXXKZrE1iC7Sah84hJyBkg2ZeX6qTrYRdxxvWISNDPJIUPCUuN66K6GLAEC1TVfQLb5VQUEaU8vHXExASC7TQ1uyOEmAYDNPHLAfZUQvrm3aI8C43nWmjEc4l85NBx2pyBW3RW2Dfm8LfrFGmh4LuIRowmyX','RGkX1uNIo63J8YGY6a2TiQ4bPxZkcogKw06lEueIRoVt7lcroyQ66OCPF3xf2pVlRXuBqsWTpHmIJkxzixQrAdCaSwRrPOTSfGrzRGT0z1uhFffChtF4vboImAHJqDUMyiERy0GRiBrmqbgBxZohVdpY3cjhQiDrb7zSsuUSFkhWGIpKGrxWFZsj2LW50zufBj4FmXL262I3awzG474YMoGva6si5eMgSn5sIdwceqAEMAGJlZquOYuVQwzkuAcBn7zQANsvNZ25HSLCQ04Ypqi3bHTymNGDl0vjXqiVg8Zlx4AZnymHpCbWDWfzJynd0gKdWsVViblFg15zKRYsxqFPCSX2mgV7tRzvjVh7lvUgRc8oclPgG1LNxhl0CGDhmzQIrjAkUihQ0LSKCpxJzAIuBoCEKhjhBGKdByeiYAyV24aQ1MXtDnyLD38wBQGrSZtvXK0g5YT6VvHS8EhTfUmnd0OwvoxHDwXCzGnCnxXZW7Hm3bRXNdJf1p5uQVv7ajmXiQukTx8yRdz42gQhWLiG5FmeJbWK4R4zqORHXTougezuF2RthvqDG7yLAvMPu4Ou8PikFF7qK67BlIh3DWKcgO2fgZbuzp2cxrJNSjyaF5aBTPCyshLYNSAJEqTZH7N8WO5nwL4yWUxKlKxSJiOpOwCYVdoNJWSP8HHTgtLQjXYrd2DuomNJTU0iW13Pv3VzBwB8IoO84pzjaxPBZTgqFAuone5up7jw6dzssIbJ7C4FGUIG2ZUj8RPzhl7m6YjaG1jKvH2SDfubYfissUPuWasIvLlnuGx3mHBFgFH60OdAtWlPWllY3QF1V5B0QBx5Mkim3viyzQogiEcGHWJ3dNIEhe6WaSRKNvY1mUETz6md2M23uQNeuDhFfFCXeezgQFchBIZN5Zuhtb1muJ2yv47M053ffhHd4ByawSMM570wVpP5xLuDHICH8OYflLC4XSjS8KEECz4tGIS1SwCSHyU2fJb6bsivDVE8PPaXA6uNLi2h6rxb644cXr1P6DOinuvuSJl3kAVSRCHLPvdGysRtDN3iwzhQpzXi1xrjnE5F1GOD6R7AOZPfEZ7EwVLsshWSyUWzfjiexsE2H6gHMlnyGesQBBC27JbO4txGKlWCJqDiAcLMxh5ikTdKLQALdRIlrYnrIkSXkrSIChgvnVr3uvh1PqDTCWqOrsoQiY3X0PxrQjA5c2mpSWamAuZFVQ3YWs2BUBsWFqqowqXGRkTLqrxHEAwgUxTFXvBvUW2nlys6stX88WFFp7Z4vO8wYwy2mc1WDkew8MCzBoHXrDwwGP5l1mncQmeOMU5TwFfJhT6G40JjB1PaNKe0rBmgdmMxveDiSnADiDleV3ric5pYDKCTnGEx56wlzMnt7446uqGs16uvJnbAVTWe2ix368d66PPgWyUJiKgE0ZhmMOKiKW2f5Hp3XRypTLlFqxxLPtI0P77yLYW6TROAmwx3ymWouRTWvIV1lGEwon0AhiKy6wRJDiGy0VoP3M766s8VAbogVXYUh7WFAej1chgxsSuU7OxF1dOtfzuneNH0UWE1F6ynN2Wum3xbzoer5rKsv2suOba80LxdeCHEKNyOyK5860x6JZhEJZIUfgMF4HTav7mtaifW4yyIVXcdxXOslBJUisGenwgE7PsdXehd0iqGKH8BBuOECjWPIuGG2aS51uRHUs31r2wxPpq4XxNcoP5B8V6T7cPINPbf7bjoMYI5aI8MRRQZBEH8aoZMaY0mhOYWeLKcCyrhf6v8eitWX4QY6wjQ5QwCloo0iS7ESCuQEjc5slwscscmRx3bKPTwV1e0tGyizKceUiwmxFiImC4me7ts1hYKk2AKdCWPwtEew3khFhV8dE2Bo1jLZRuTeCCSjuZKuejLTV0E7Xw3TxmAT7tlDrsd8JuDRuqriBF1TLkd0knIWG4cehoOZIEVVjLKTEABMAYOWm6JORttKrsx0FfAlzRcBJlLQofVhD3xVltnrIVYbczWkai0QQSiySib2c1WYa5t2FG0qaMNwGZf1BZagXrRQgexMS428EBrtmSCZYoNAcfVzSrCC6M5jkRyBHw','VZ7DnA7vcofPtMwPPulenNpC7ErJPaLsWy2XipWF02D1ZwzXCwC8hJ6MrII3PKYGLklG0SzrMqU0','BfjqAIQ6gwX3Xhjl338BqTJaMZUKxzMcdTovIPF6iD3lXeW4szUglzWNmFKXlYQ71cRQM1v0BAZwUqf1lRZfCsKnPlJIDdgy0JmHrfVHGGy84c3NMf7TRuNOeqj7xUYCV','Aox4fssjHKLaZwTS0Bq',57753,NULL,'C:\DOCS\TEMP75');
exit when c%notfound;
end loop;
close c;
commit;
end;

Related

How to remove ORA-01562: Failed to extend rollback segment error while updating 100 million rows

A table is having 100 million records and I need to update a column by adding 10% into the salary of each employee. when I execute update statement I am getting this error:
ORA-01562: Failed to extend rollback segment
How can I update this column for the best performance result?
update employee
set salary = salary + (salary*10/100)
OR
declare
i number(10);
limit number(10) := 100000;
begin
for i in 1 .. limit loop
update employee
set salary = salary + (salary*10/100)
where rownum = i;
limit := limit + 100000;
end loop;
end;
Looks like you are using Oracle version 8i or prior, as the rollback segments have been replaced with undo segments from Oracle 9i onwards.
To solve the problem, I would suggest you to check the trace file to see which rollback segment is creating the problem, then create a bigger rollback segment depending upon the update transaction size.
Try this:
DECLARE
CURSOR CUR
IS
SELECT ROWID, A.*
FROM YOUR_SALARY_TABLE A;
TYPE CUR_TYPE IS TABLE OF CUR%ROWTYPE
INDEX BY PLS_INTEGER;
L_CUR CUR_TYPE;
LIM NUMBER := 100000; -- Update chunk size
BEGIN
OPEN CUR;
LOOP
FETCH CUR BULK COLLECT INTO L_CUR LIMIT LIM;
FOR INDX IN 1 .. L_CUR.COUNT
LOOP
UPDATE YOUR_SALARY_TABLE S
SET S.SALARY_COLUMN = S.SALARY_COLUMN * 2 -- Multiplying here
WHERE ROWID = L_CUR (INDX).ROWID;
END LOOP;
COMMIT;
EXIT WHEN L_CUR.COUNT < LIM;
END LOOP;
CLOSE CUR;
END;
You can try this approach: link
Information about parallel: link
We can use FORALL also to achieve what is required. Hope this below snippet helps.
DROP TABLE test_so1
/
CREATE TABLE TEST_SO1
( COL1 NUMBER, COL2 VARCHAR2(100)
)
/
--Insert values
INSERT INTO TEST_SO1
SELECT LEVEL,'AVRAJIT'||LEVEL FROM DUAL CONNECT BY LEVEL < 10000
/
--FORALL UPDATE
DECLARE
type TEST_REC
IS
RECORD
(
COL1 NUMBER,
COL2 VARCHAR2(100),
col3 VARCHAR2(100));
type TEST_TAB
IS
TABLE OF TEST_REC;
LV_TAB TEST_TAB;
CURSOR LV_CUR
IS
SELECT col1,col2,rowid FROM TEST_SO1;
BEGIN
OPEN LV_CUR;
LOOP
FETCH LV_CUR BULK COLLECT INTO LV_TAB LIMIT 1000;
EXIT
WHEN LV_TAB.COUNT=0;
FORALL I IN LV_TAB.FIRST..LV_TAB.LAST
UPDATE TEST_SO1 SET COL2 = 'shubhojit' WHERE ROWID = lv_tab(i).col3;
COMMIT;
END LOOP;
END;
/

ORACLE SQL%ROWCOUNT doesn't work inside a cursor fetch

In my following code, I'm unable to get the inserted row count within a cursor fetch.
...
row_count NUMBER:= 0;
BEGIN
OPEN object_id_cur(id, c_bool);
LOOP
FETCH object_id_cur INTO l_object_id;
EXIT WHEN object_id_cur%NOTFOUND;
INSERT INTO table1(
id,
num
)
SELECT t2.r_object_id,
t2.num
FROM table2
WHERE t2.r_object_id = l_object_id.r_object_id;
row_count:= row_count + SQL%ROWCOUNT;
-- I also tried dbms_output.put_line(SQL%ROWCOUNT);
END LOOP;
CLOSE object_id_cur;
COMMIT;
dbms_output.put_line('insert count= ' || row_count || ' rows inserted...');
END;
My obtained result is: count = rows inserted... count is blank. If I move the insert outside the cursor fetch, then the row count works just fine. Is there a logical explanation for this? Thanks!
count is a reserved keyword. Use "count" or some other identifer say cnt. Also, add the missing semicolon at then end of the increment statement.
declare
cnt number := 0;
begin
. . .
cnt := cnt + SQL%ROWCOUNT;
. . .
Demo:
SQL> create table t (id int);
Table created.
SQL> declare
2 cursor c is
3 select level n from dual connect by level <= 100; -- produces 100 rows
4 n int;
5 cnt number := 0;
6 begin
7 open c;
8 loop
9 fetch c into n;
10 exit when c%notfound;
11 insert into t (id)
12 select n from dual union all
13 select n from dual; -- insert each value twice
14 cnt := cnt + sql%rowcount;
15 end loop;
16 close c;
17 dbms_output.put_line(cnt); -- should be 200
18 end;
19 /
200 -- correct output
PL/SQL procedure successfully completed.
SQL>
As you can see above, the SQL%rowcount works correctly. It could be that your below select query is not producing any rows.
SELECT t2.r_object_id,
t2.num
FROM table2
WHERE t2.r_object_id = l_object_id.r_object_id;
SQL%ROWCOUNT return the number of rows fetched/processed by the last DML executed. If the DML fails after fetching 1 row, due to any reason, SQL%ROWCOUNT will return only 1, the number of rows fetched/processed so far. It wont give you the total count. I did a simple PLSQL block and getting the SQL%ROWCOUNT working fine. Seems there is something else which is not working in your code.
declare
num number := 0;
begin
for i in 1 .. 10
loop
insert into a_table (id)
values (i);
num := num + sql%rowcount;
end loop;
dbms_output.put_line (num);
end;

How to store a column of result of select query in an array?

If we have a column in a table of type number, how can we store the result of select query on that column in an array ?
This sample uses a list (table of numbers) to achieve this, because i find
those lists much more handy:
CREATE OR REPLACE TYPE numberlist AS TABLE OF NUMBER;
DECLARE
v_numberlist numberlist;
BEGIN
SELECT intval numbercolumn
BULK COLLECT INTO v_numberlist
FROM lookup;
FOR i IN 1..v_numberlist.count
LOOP
dbms_output.put_line( v_numberlist(i) );
END LOOP;
END;
Create a type which store number:-
CREATE OR REPLACE TYPE varray is table of number;
--write your select query inside for loop () where i am extracting through level
declare
p varray := varray();
BEGIN
for i in (select level from dual connect by level <= 10) loop
p.extend;
p(p.count) := i.level;
end loop;
for xarr in (select column_value from table(cast(p as varray))) loop
dbms_output.put_line(xarr.column_value);
end loop;
END;
output:-
1
2
3
4
5
6
7
8
9
10
Just an option to use some native SQL datatype. Hope it helps.
SET SERVEROUTPUT ON;
DECLARE
lv_num_tab DBMS_SQL.NUMBER_TABLE;
BEGIN
SELECT LEVEL BULK COLLECT INTO lv_num_tab FROM DUAL CONNECT BY LEVEL < 10;
FOR I IN lv_num_tab.FIRST..lv_num_tab.LAST
LOOP
dbms_output.put_line(lv_num_tab(i));
END LOOP;
END;
You may also want to put the whole select in a table. You can use a BULK COLLECT to an array:
CREATE OR REPLACE TYPE t_my_list AS TABLE OF VARCHAR2(100);
CREATE OR REPLACE
PROCEDURE get_tables(p_owner in varchar2)
as
v_res t_my_list;
v_qry varchar2(4000) := '';
begin
v_qry := ' SELECT table_name from all_tables where owner='''||p_owner||'''';
dbms_output.put_line(v_qry);
-- all at once in the table
execute immediate v_qry bulk collect into v_res;
FOR I in 1..v_res.count
loop
dbms_output.put_line(v_res(i));
end loop;
exception
when others then
raise;
end get_tables;
/
begin
get_tables('E') ;
end;
/

Oracle Bulk Collect with Limit and For All Not Processing All Records Correctly

I need to process close to 60k records of an Oracle table through a stored procedure. The processing is that for each such row, I need to delete and update a row in a second table and insert a row in a third table.
Using cursor looping, the procedure takes around 6-8 hours to complete. If I switch to Bulk Collect with Limit, the execution time is reduced but processing is not correct. Following is the bulk collect version of the procedure
create or replace procedure myproc()
is
cursor c1 is select col1,col2,col3 from tab1 where col4=3;
type t1 is table of c1%rowtype;
v_t1 t1;
begin
open c1;
loop
fetch c1 bulk collect into v_t1 limit 1000;
exit when v_t1.count=0;
forall i in 1..v_t1.count
delete from tab2 where tab2.col1=v_t1(i).col1;
commit;
forall i in 1..v_t1.count
update tab2 set tab2.col1=v_t1(i).col1 where tab2.col2=v_t1(i).col2;
commit;
forall i in 1..v_t1.count
insert into tab3 values(v_t1(i).col1,v_t1(i).col2,v_t1(i).col3);
commit;
end loop;
close c2;
end;
For around 20k of these records, the first delete operation is processed correctly but subsequent update and insert is not processed. For the remaining 40k records all three operations are processed correctly.
Am I missing something? Also what is the maximum LIMIT value I can use with Bulk Collect?
You should try using SAVE EXCEPTIONS clause of FORALL, something like (untested):
create or replace procedure myproc
as
cursor c1 is select col1,col2,col3 from tab1 where col4=3;
type t1 is table of c1%rowtype;
v_t1 t1;
dml_errors EXCEPTION;
PRAGMA exception_init(dml_errors, -24381);
l_errors number;
l_errno number;
l_msg varchar2(4000);
l_idx number;
begin
open c1;
loop
fetch c1 bulk collect into v_t1 limit 1000;
-- process v_t1 data
BEGIN
forall i in 1..v_t1.count SAVE EXCEPTIONS
delete from tab2 where tab2.col1=v_t1(i).col1;
commit;
EXCEPTION
when DML_ERRORS then
l_errors := sql%bulk_exceptions.count;
for i in 1 .. l_errors
loop
l_errno := sql%bulk_exceptions(i).error_code;
l_msg := sqlerrm(-l_errno);
l_idx := sql%bulk_exceptions(i).error_index;
-- log these to a table maybe, or just output
end loop;
END;
exit when c1%notfound;
end loop;
close c2;
end;

Bulk Collect Oracle

Can bulk collect be done if data is getting inserted into table A from Table B and while selecting data, substr, instr, trunc functions has been used on columns fetched?
INSERT INTO A
SELECT
DISTINCT
SUBSTR(b.component, 1, INSTR(b.component, ':', 1) - 1),
TRUNC(c.end_dt, 'DDD'),
FROM
B b,
C c
WHERE
TRUNC(c.end_dt)=TRUNC(b.last_Date, 'DDD') ;
How can I insert data into table A using bulk collect?
The only reason you'd use Bulk Collect and FORALL to insert rows is when you absolutely need to process/insert rows in chunks. Otherwise always use SQL.
DECLARE
CURSOR c_data IS
SELECT * FROM source_tab;
--
TYPE t_source_tab IS TABLE OF source_tab%ROWTYPE;
l_tab t_source_tab;
v_limit NUMBER:= 1000;
BEGIN
OPEN c_data;
LOOP
FETCH c_data BULK COLLECT INTO l_tab LIMIT v_limit;
EXIT WHEN l_tab.count = 0;
-- Insert --
FORALL i IN l_tab.first .. l_tab.last
INSERT INTO destination_tab VALUES l_tab(i);
COMMIT;
-- prints number of rows processed --
DBMS_OUTPUT.PUT_LINE ('Inserted ' || SQL%ROWCOUNT || ' rows:');
-- Print nested table of records - optional.
-- May overflow the buffer and slow down the performance if you process many rows.
-- Use for testing only and limit the rows with Rownum or Row_Number() in cursor query:
FOR i IN l_tab.FIRST..l_tab.LAST -- or l_tab.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE (l_tab(i).hire_date ||chr(9)||l_tab(i).last_name ||chr(9)||l_tab(i).first_name);
END LOOP;
END LOOP;
CLOSE c_data;
END
/

Resources