Log errors includes the name of the failed constraint. And the error table has the values from the failed columns. So you could bulk-select those with the constraint you want to re-run:
create table t (
x int constraint x_u unique,
y int constraint y_u unique
);
exec dbms_errlog.create_error_log ('t');
declare
type rec is table of t%rowtype index by binary_integer;
r rec;
fail rec;
begin
r(1).x := 1;
r(1).y := 1;
r(2).x := 1;
r(2).y := 2;
r(3).x := 3;
r(3).y := 1;
forall i in 1 .. r.count
insert into t values (r(i).x, r(i).y)
log errors reject limit unlimited;
select x, y
bulk collect into fail
from err$_t
where ora_err_mesg$ like '%Y_U%';
for i in 1 .. fail.count loop
dbms_output.put_line(
'X: ' || fail(i).x ||
'; Y: ' || fail(i).y
);
end loop;
end;
/
X: 3; Y: 1
Then manipulate your array as needed before re-inserting.
Or, if you're happy with only dealing with failures from one constraint, you could always ignore the other!
The ignore_row_on_dupkey_index silently swallows up ORA-00001 exceptions. So you can use this to only throw exceptions on one of the constraints!
Then you could use either log errors or forall save exceptions:
rollback;
declare
type rec is table of t%rowtype index by binary_integer;
r rec;
bulk_errors exception;
pragma exception_init (bulk_errors, -24381);
begin
r(1).x := 1;
r(1).y := 1;
r(2).x := 1;
r(2).y := 2;
r(3).x := 3;
r(3).y := 1;
forall i in 1 .. r.count save exceptions
insert /*+ ignore_row_on_dupkey_index(t,x_u) */
into t values (r(i).x, r(i).y);
exception
when bulk_errors then
for i in 1 .. sql%bulk_exceptions.count loop
dbms_output.put_line(
'X: ' || r(sql%bulk_exceptions (i).error_index).x ||
'; Y: ' || r(sql%bulk_exceptions (i).error_index).Y
);
end loop;
end;
/
X: 3; Y: 1