I found solution by using this kind of flow:
PROCEDURE FOO_FAST(IN_FOO IN VARCHAR2) IS
CURSOR CUR IS SELECT COL1,COL2,COL3 FROM SOME_TABLE;
TYPE RT_CUR IS TABLE OF CUR%ROWTYPE;
LT_CUR RT_CUR;
DML_EXCEPTION EXCEPTION;
PRAGMA EXCEPTION_INIT(DML_EXCEPTION, -24381);
BEGIN
OPEN CUR;
LOOP
FETCH CUR BULK COLLECT INTO LT_CUR LIMIT 1000;
EXIT WHEN LT_CUR.COUNT = 0;
BEGIN
FORALL I IN 1 .. LT_CUR.COUNT SAVE EXCEPTIONS
INSERT INTO OTHER_TABLE (C1,C2,C3) VALUES (LT_CUR(I).COL1,LT_CUR(I).COL2,LT_CUR(I).COL3);
EXCEPTION
WHEN DML_EXCEPTION THEN
FOR I IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
DBMS_OUTPUT.PUT_LINE(SQLERRM(-SQL%BULK_EXCEPTIONS(1).ERROR_CODE));
LT_CUR.DELETE(SQL%BULK_EXCEPTIONS(1).ERROR_INDEX);
END;
FORALL I IN INDICES OF LT_CUR
UPDATE THIRD_TABLE T SET T.C_SUM = LT_CUR(I).COL2 + LT_CUR(I).COL3 WHERE T.C_ID = LT_CUR(I).COL1);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERROR || ': ' || SQLERRM);
END FOO_FAST;
In this flow:
- All exceptions ocured in
INSERT
will be stored inSQL%BULK_EXCEPTIONS
collection - Each exception will be logged by
DBMS_OUTPUT.PUT_LINE
(in real life in log table byAUTONOMOUS TRANSACTION
procedure) - Each error index of
LT_CUT
will be removed byDELETE
method on collection. - Only "good" lines will be used in
UPDATE
becauseINDICES OF
clause allows a bulk operation on a sparse collection by removing the reference to specific elements