Oracle PL/SQL - 如何在异常子句的单独表中捕获坏数据?
Posted
技术标签:
【中文标题】Oracle PL/SQL - 如何在异常子句的单独表中捕获坏数据?【英文标题】:Oracle PL/SQL - How to catch the bad data in a separate table in the exception clause? 【发布时间】:2017-03-02 04:25:45 【问题描述】:下面是代码
declare
cursor c_data
is
select * from test_product_u;
begin
for i in c_data
loop
insert into test_product_u_final
(PRODUCT_NO, CREATED_DATE, DATE_FORMAT)
values (i. PRODUCT_NO, i.CREATED_DATE,i.DATE_FORMAT);
end loop;
exception when others then
---->'I want to catch the bad data here ? What are the options apart from the sqlerror message I want the data itself possibly in a VARCHAR column'<----
end;
我想在异常子句中捕获坏数据?除了获取 sqlerror 消息之外还有哪些选项我希望数据本身可能在 VARCHAR 列中?有可能吗。
DW 加载捕获无效数据时通常会发生什么?
【问题讨论】:
我们在谈论多少数据? 本例仅假设 10 条记录,但对于 DW 每晚加载将超过 500,000 条记录。 那么 10 行的方法与 500,000 行的方法大不相同 :) 你想捕捉什么样的错误? 任何不符合表数据定义的错误,如NOT NULL或DATA TYPE MISMATCH。无论错误如何,我都希望将传入数据的快照记录到异常表中。 【参考方案1】:根据代码示例,您只需将 BEGIN END 放入 LOOP 即可成功将错误记录在单独的错误表中。下面我举例说明了。希望这会有所帮助。
DECLARE
CURSOR c_data
IS
SELECT * FROM test_product_u;
BEGIN
FOR i IN c_data
LOOP
BEGIN
INSERT
INTO test_product_u_final
(
PRODUCT_NO,
CREATED_DATE,
DATE_FORMAT
)
VALUES
(
i. PRODUCT_NO,
i.CREATED_DATE,
i.DATE_FORMAT
);
EXCEPTION
WHEN OTHERS THEN
INSERT
INTO bad_data_tab VALUES
(
i.product_no
||';'
||i.created_date
||';'
||i.date_format
);
END;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20009,SQLERRM,TRUE);
END;
【讨论】:
所以如果有一个坏行,上面的代码将所有行插入到坏表中。您可以拆分循环以仅将坏行推送到实际目的地吗? 它完全按照您的要求进行操作。将好的行插入目标并将坏记录加载到 bad_table。 为什么按照我的回答,当您可以使用基于集合的 SQL 更快(数量级)更快地执行此操作时(或我的团队所说的“慢慢来”)。 . 是的,你是对的。我的目的是让我的答案更接近 OP 问题,以便只需进行最少的更改。【参考方案2】:从根本上说,采用的方法是尽可能多地使用基于集合的处理,这将(字面上)比逐行方法快 100 倍。大多数数据库验证都可以使用基于集合的 SQL 的强大功能来完成。此外,如果你有硬件(CPU 和 IO 带宽),很容易并行化以获得更高的性能。 大多数 DW 加载采用“瀑布式”方法,从一个表加载到另一个表,直到数据最终干净为止。 以你的一个数据检查为例,NOT NULL,它可以写成这样,使用多表插入。
insert /*+ APPEND */ all
when ( col is null )
then
into table product_error_1 ( PRODUCT_NO, CREATED_DATE, DATE_FORMAT) values (PRODUCT_NO, CREATED_DATE, DATE_FORMAT )
else
into table product_stage_2 ( PRODUCT_NO, CREATED_DATE, DATE_FORMAT ) values ( PRODUCT_NO, CREATED_DATE, DATE_FORMAT )
select * from test_product_u
/
【讨论】:
【参考方案3】:create table test_product_u
(product_no varchar2(1024),
created_date varchar2(1024),
date_format varchar2(1024) default 'yyyy-mon-dd');
create table test_product_u_final
(product_no varchar2(1024),
created_date date not null,
date_format varchar2(1024) default 'yyyy-mon-dd');
insert into test_product_u(product_no, created_date)
values('A', '2017-mar-02');
insert into test_product_u(product_no, created_date)
values('B', null);
insert into test_product_u(product_no, created_date)
values('C', '28-february-2017');
commit;
方法一:
begin
dbms_errlog.create_error_log('TEST_PRODUCT_U_FINAL', 'TEST_PRODUCT_U_FINAL$ERR') ;
end;
declare
cursor c_data is
select * from test_product_u;
begin
for i in c_data loop
insert into test_product_u_final
(product_no, created_date, date_format)
values
(i. product_no, i.created_date, i.date_format) log errors into test_product_u_final$err
('INSERT') reject limit unlimited;
end loop;
end;
方法二:
declare
cursor c_data is
select * from test_product_u;
begin
for i in c_data loop
begin
insert into test_product_u_final
(product_no, created_date, date_format)
values
(i. product_no, i.created_date, i.date_format);
exception
when others then
dbms_output.put_line('========== Exception (Start) ===============');
dbms_output.put_line('Product: ' || i.product_no);
dbms_output.put_line('Created Date: ' || i.created_date);
dbms_output.put_line('Date Format: ' || i.date_format);
dbms_output.put_line('Error Code: ' || sqlcode);
dbms_output.put_line('Error Text: ' || sqlerrm);
dbms_output.put_line('Error Trace: ' || dbms_utility.format_error_backtrace);
dbms_output.put_line('========== Exception (End) ===============');
end;
end loop;
end;
并输出:
========== Exception (Start) ===============
Product: A
Created Date: 2017-mar-02
Date Format: yyyy-mon-dd
Error Code: -1861
Error Text: ORA-01861: literal does not match format string
Error Trace: ORA-06512: at line 7
========== Exception (End) ===============
========== Exception (Start) ===============
Product: B
Created Date:
Date Format: yyyy-mon-dd
Error Code: -1400
Error Text: ORA-01400: cannot insert NULL into ("FCI"."TEST_PRODUCT_U_FINAL"."CREATED_DATE")
Error Trace: ORA-06512: at line 7
========== Exception (End) ===============
【讨论】:
以上是关于Oracle PL/SQL - 如何在异常子句的单独表中捕获坏数据?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 select 的 where 子句中替换 oracle pl/sql 变量
oracle 形式:pl/sql 中 where 子句中的 max 子句