You can't use the error logging mechanism for this as it isn't designed to support it. It errors at the point it tries to create the duplicate in the table - the first value it tries to insert for pass_no
10 is valid on its own - so it would have to distinguish between data that already existed and multiple values coming from the insert, to start with. So you'd need to roll your own.
One option is to create your own table to hold the duplicates, and use an insert all
to decide which values belong in each table:
create table tbl_target_dup (
cus_no number,
pass_no number
);
insert all
when cus_count = 1 and pass_count = 1 then
into tbl_target values (cus_no, pass_no)
else
into tbl_target_dup values (cus_no, pass_no)
select a.pass_no, b.cus_no,
count(*) over (partition by a.pass_no) as pass_count,
count(*) over (partition by b.cus_no) as cus_count
from tbl_one a
join tbl_two b on b.pass_no = a.pass_no;
This allows you to have more columns than those affected by the PK/UK, and insert them only into the real table if you prefer, or a subset into the 'error' table. With just those two columns in each table you get:
select * from tbl_target;
CUS_NO PASS_NO
---------- ----------
103 20
select * from tbl_target_dup;
CUS_NO PASS_NO
---------- ----------
101 10
102 10
You could do the same thing with two inserts based on the same select
, one with a subquery checking that both counts are 1, other checking that at least one is not, but this might perform better.