【问题标题】:Log all errors for a value into error log if a single row fails如果单行失败,则将值的所有错误记录到错误日志中
【发布时间】:2014-04-22 12:34:55
【问题描述】:

我正在尝试维护数据完整性并将错误记录到错误表中。我有 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 值都应该插入到错误表中;不是,一个进入目标,一个进入错误表。我不想使用存在语句,因为我无法记录所有违反的值。

我该怎么做呢?

【问题讨论】:

  • 如果只有一行失败,为什么要记录整个语句?
  • 不是整个语句,只有违规错误 pass_no = 20 可以,但 10 不行
  • 从数据库的角度来看,第一条记录没有任何问题。您将需要手动添加逻辑。您可以使用 MERGE、pl/sql 过程、dbloader 或触发器。顺便说一句,这种方式记录错误会影响性能。

标签: oracle oracle11g error-logging


【解决方案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,另一个检查至少一个不是,但这可能会执行得更好。

【讨论】:

  • 感谢您提供的“全部插入”方法,它很有帮助。
猜你喜欢
  • 2018-12-26
  • 1970-01-01
  • 1970-01-01
  • 2012-07-17
  • 1970-01-01
  • 2015-07-07
  • 2019-02-19
  • 1970-01-01
  • 2011-07-25
相关资源
最近更新 更多