日期:2014-05-16 浏览次数:20727 次
对于大批量的DML操作中出现的错误,除了使用DML error logging特性来记录在DML期间出现的错误之外,使用批量SQL语句FORALL的SAVE
EXCEPTIONS是不错的选择之一。DML error logging特性的使用较FORALL之 SAVE EXCEPTIONS相对简单,也存在一些不足,如每一个被操作的DML
对象需要创建相应的对应的日志表,不利于集中管理。本文对DML error logging这个不利于集中管理的特性使用FORALL 之 SAVE EXCEPTIONS
方式来完成。
下面的示例来自一个实际的应用,撇开原始的表名与实际应用中的处理过程,仅仅通过简单示例来展现。
1、两个不同的DB,假定设定为数据库A和数据库B(为简化,在同一个DB上来演示)。
2、需要将数据库A的一些表的数据同步到数据库B对应的目的表
3、如果同步的过程中出现某条特定的记录错误,则写该记录产生的错误信息(含表名,主键)到日志表,并将其原表同步状态更新为N,否则更新为Y
4、如果非由于INSERT产生的错误信息,则要求写过程名及对应的错误信息到日志表
如对于批量SQL较为熟悉,请直接阅读下文,否则,请参阅阅读本文所需要的相关知识:
批量SQL之 FORALL 语句
批量SQL之 BULK COLLECT 子句
PL/SQL 集合的初始化与赋值
PL/SQL 联合数组与嵌套表
PL/SQL 变长数组
PL/SQL --> PL/SQL记录
一、创建演示环境
为简化,下面的演示代码在同一个数据库上完成,在不同的DB上来完成仅仅是需要设定DB LINK而已。
-->创建用于演示的源表emp_source,其数据来自scott.emp scott@CNMMBO> create table emp_source as select empno,ename,sal from emp; Table created. -->为源表增加一个字段is_sync,用于记录是否同步成功 scott@CNMMBO> alter table emp_source add is_sync char(1); Table altered. -->创建目的表 scott@CNMMBO> create table emp_dest as select empno,ename,sal from emp_source where 1=0; Table created. -->创建记录错误信息的日志表 scott@CNMMBO> create table err_log_tbl(log_seq number(12) not null, log_time date not null, 2 sp_name varchar2(100),table_name varchar2(30),table_pk varchar2(30),err_msg varchar2(2000)); Table created. -->为表emp_dest 添加约束用于在insert过程中触发错误产生 scott@CNMMBO> alter table emp_dest add constraint ck_sal check(sal>500); Table altered. scott@CNMMBO> alter table emp_dest modify(ename constraint nn_ename not null); Table altered. -->创建一个用于错误日志表上的sequence CREATE SEQUENCE SCOTT.ERR_SEQ START WITH 20 MAXVALUE 999999999999999999999999999 MINVALUE 0 NOCYCLE NOCACHE NOORDER; -->创建一个函数用于获取sequence CREATE OR REPLACE FUNCTION SCOTT.gen_new_err_seq RETURN err_log_tbl.log_seq%TYPE IS newrecid err_log_tbl.log_seq%TYPE; BEGIN SELECT ERR_SEQ.NEXTVAL INTO newrecid FROM DUAL; RETURN newrecid; END; /
二、使用下面的PL/SQL块演示
-->下面的演示代码可以封装到包 DECLARE c_sp_name CONSTANT VARCHAR2 (50) := 'anonymity_plsql_block'; c_process_name CONSTANT VARCHAR2 (20) := 'ins_emp_dest'; c_table_name VARCHAR2 (30) := 'emp_dest'; debugpos bo_common_pkg.debug_pos_type := 0; v_limit PLS_INTEGER := 5; -->定义游标fetch时提取数量的限制数,由于emp_source记录较少,此处设定为5 err_msg VARCHAR2 (1000); CURSOR cur_emp -->声明游标从源表取数据 IS SELECT empno, ename, sal FROM emp_source WHERE is_sync IS NULL; TYPE emp_tab_type IS TABLE OF cur_emp%ROWTYPE; emp_tab emp_tab_type; -->声明基于游标的嵌套表 TYPE err_rec_type IS TABLE OF err_log_tbl%ROWTYPE; err_tab err_rec_type := err_rec_type (); -->声明基于err_log_tab的嵌套表并初始化 sub_proc_exp EXCEPTION; -->定义了两个异常 bulk_error EXCEPTION; PRAGMA EXCEPTION_INIT (bulk_error, -24381); BEGIN debugpos := 10; OPEN cur_emp; LOOP BEGIN