Как через SQL%BULK_EXCEPTIONS получить индекс на элементы коллекции, которые вызвали исключения?
Я взял этот код в качестве примера из этого ответа:
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE) IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
UPDATE EMPLOYEES
---trying to rasie an exception by using a calculation
SET SALARY=SALARY * 999999999999
WHERE ID_E= V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
---I'm printing the value of the exception array.
dbms_output.put_line('exception Raised for record' ||V_EMP_ID(i));
END LOOP;
END;
/
Объясните, как V_EMP_ID(i) может указывать на элемент, который вызвал исключение?
Так как i берётся из 1 ... SQL%BULK_EXCEPTIONS.COUNT', то при одной ошибке V_EMP_ID(i) всегда будет указывать на первый элемент коллекции.
Свободный перевод вопроса How does FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT point to the elements of the collection that threw the exceptions от участника @AnuC
Ответы (1 шт):
Принятый ответ не значит, что он полность верный.
Из оф. документации кап. 12.4.1.4 Handling FORALL Exceptions After FORALL Statement Completes:
SQL%BULK_EXCEPTIONS(i).ERROR_INDEX is the number of the DML statement that failed.
Порядковый номер DML это тоже самое, что индекс на элемент коллекции в FORALL.
Попробуйте следующий простой рабочий пример:
create table tab (id, val check (val<=3)) as
select rownum, rownum from dual connect by level<=3
/
declare
type idtab is table of int;
ids idtab;
begin
select id bulk collect into ids
from tab;
declare
forallexcp exception;
pragma exception_init (forallexcp, -24381);
begin
forall i in 1..ids.count save exceptions
update tab set val = val + 1
where id = ids(i);
exception when forallexcp then
dbms_output.put_line (
sql%rowcount||' row(s) inserted ('||sql%bulk_exceptions.count||' with error).');
for i in 1..sql%bulk_exceptions.count loop dbms_output.put_line (
'id='||ids(sql%bulk_exceptions(i).error_index)||' sqlerrm='||
sqlerrm (-(sql%bulk_exceptions(i).error_code)));
end loop;
end;
end;
/
Результат:
2 row(s) inserted (1 with error).
id=3 sqlerrm=ORA-02290: check constraint (.) violated