Вы можете использовать save exceptions
clause of the forall
statement, чтобы собрать ошибки, а затем используйте the sql%bulk_exceptions
implicit cursor attribute, чтобы узнать, что на самом деле произошло. Там в an example в этой документации, но в вашем случае вы можете сделать (используя составленную таблицу и данные):
create table your_table (val1 number primary key, val2 number, val3 number, val4 number, val5 number);
declare
type l_table_type is table of your_table%rowtype;
l_table l_table_type := l_table_type();
dml_errors exception;
pragma exception_init(dml_errors, -24381);
begin
l_table.extend;
l_table(l_table.count).val1 := 1;
l_table(l_table.count).val2 := 1.2;
l_table(l_table.count).val3 := 1.3;
l_table(l_table.count).val4 := 1.4;
l_table(l_table.count).val5 := 1.5;
l_table.extend;
l_table(l_table.count).val1 := 2;
l_table(l_table.count).val2 := 2.2;
l_table(l_table.count).val3 := 2.3;
l_table(l_table.count).val4 := 2.4;
l_table(l_table.count).val5 := 2.5;
l_table.extend;
l_table(l_table.count).val1 := 1;
l_table(l_table.count).val2 := 3.2;
l_table(l_table.count).val3 := 3.3;
l_table(l_table.count).val4 := 3.4;
l_table(l_table.count).val5 := 3.5;
forall x in l_table.first .. l_table.last save exceptions
insert
into your_table values
(
l_table(x).val1,
l_table(x).val2,
l_table(x).val3,
l_table(x).val4,
l_table(x).val5
);
exception
when dml_errors then
for i in 1..sql%bulk_exceptions.count loop
dbms_output.put_line('Index ' || sql%bulk_exceptions(i).error_index
|| ' error ' || -sql%bulk_exceptions(i).error_code);
dbms_output.put_line(' val1: ' || l_table(sql%bulk_exceptions(i).error_index).val1);
dbms_output.put_line(' val2: ' || l_table(sql%bulk_exceptions(i).error_index).val2);
dbms_output.put_line(' val3: ' || l_table(sql%bulk_exceptions(i).error_index).val3);
dbms_output.put_line(' val4: ' || l_table(sql%bulk_exceptions(i).error_index).val4);
dbms_output.put_line(' val5: ' || l_table(sql%bulk_exceptions(i).error_index).val5);
end loop;
end;
/
Это производит вывод:
PL/SQL procedure successfully completed.
Index 3 error -1
val1: 1
val2: 3.2
val3: 3.3
val4: 3.4
val5: 3.5
Первый элемент коллекции с val1
набора в один был вставлен успешно; второй получил уникальное исключение ограничения и не было - но он был помещен в механизм избыточного исключения вместо того, чтобы вызвать ошибку всего оператора.
Затем вы можете решить, следует ли поднимать исключение (или повторно поднимать) или сразу откат (возможно, до точки сохранения); или зафиксировать вставки, которые не вызвали ошибку.
Вы также можете вставлять те же значения в таблицу отклоненных элементов, но вам нужно быть немного осторожными, если вы откатываете другие изменения (предположительно, вы не были бы в этом сценарии).
Вы не можете непосредственно использовать другой forall
, чтобы сделать это - ссылаясь на l_table(sql%bulk_exceptions(i).error_index).val1
внутри пункта values()
бросает ORA-00911 из-за %
характера - так что вам либо придется делать отдельные вставки внутри цикла for
или копия значения для другой коллекции и объемной вставки. Если вы не ожидаете большого количества отклонений, отдельные вставки могут быть достаточно хорошими.