如果单行失败,请将值的所有错误记录到错误日志中

时间:2014-04-22 12:34:56

标签: oracle oracle11g error-logging

我正在尝试维护数据完整性并将错误记录到错误表中。我有3个具有唯一约束的表和1个错误表:

create table tbl_one ( 
pass_no number, 
constraint tbl_one_u01 unique (pass_no) );
insert into tbl_one values(10);
insert into tbl_one values(20);

create table tbl_two ( 
cus_no number, 
cus_name varchar2(50), 
pass_no number,
constraint tbl_two_u01 unique (cus_no) );
insert into tbl_two values( 101, 'NameX',10);
insert into tbl_two values( 102, 'NameY',10);
insert into tbl_two values( 103, 'NameZ',20);

create table tbl_target (
cus_no number,
pass_no number,
constraint tbl_target_u01 unique (cus_no),
constraint tbl_target_u02 unique (pass_no));

exec dbms_errlog.create_error_log('tbl_target','tbl_target_err');

我正在尝试将所有ORA-00001错误记录到错误表tbl_target_err,如下所示:

begin
    insert into tbl_target
    select a.pass_no, b.cus_no
      from tbl_one a 
     inner join tbl_two b on b.pass_no = a.pass_no
       log errors into tbl_target_err reject limit 10;
end;

结果是:

select * from tbl_target;
-------------------
CUS_NO    PASS_NO
101    10
103    20

和错误表:

CUS_NO    PASS_NO
102    10

我需要将所有违规错误放入错误表中。如果违反了pass_no 10 的值,则所有 10 值都应插入错误表中;不,一个进入目标,一个进入错误表。我不想使用exists语句,因为我无法记录所有违反的值。

我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

您无法使用错误日志记录机制,因为它不是为支持它而设计的。它在尝试在表中创建副本时出错 - 它试图为pass_no 10插入的第一个值本身是有效的 - 因此它必须区分已存在的数据和即将出现的多个值从插入开始。因此,您需要自己动手。

一个选项是创建自己的表来保存重复项,并使用insert all来确定每个表中属于哪些值:

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;

这允许您拥有比受PK / UK影响的列更多的列,并且如果您愿意,只将它们插入到真实表格中,或者将其插入到“错误”中。表。您只需在每个表格中获得这两列:

select * from tbl_target;

    CUS_NO    PASS_NO
---------- ----------
       103         20 

select * from tbl_target_dup;

    CUS_NO    PASS_NO
---------- ----------
       101         10 
       102         10 

SQL Fiddle demo

你可以使用基于相同select的两个插入执行相同的操作,一个子查询检查两个计数是1,其他检查至少一个不是,但这可能表现更好。