构建测试用例的思路是:loop循环进行数据处理的时候是先得到结果集再进行主体逻辑处理还是一边循环得到结果,一边处理主体逻辑!
创建测试用表:
<span style="font-family:Verdana;font-size:18px;">create table t(id number,month varchar2(20));
create table t1(id number,log_date date default sysdate,log_context varchar2(3000),who varchar2(30) default user);
create table error_trigger(error_no varchar2(6),error_message varchar2(200),trigger_name varchar2(50),trgger_user varchar2(30),trigger_date date,error_comment varchar2(300));
create table t2(id number,monthly date);</span>
为t1表增加序列,触发器:
<span style="font-family:Verdana;font-size:18px;">Create sequence seq_jz
Increment by 1
Start with 1
Maxvalue 999999
Minvalue 1
Nocycle
nocache;
/
create or replace trigger t1_insert
before insert on scott.t1
for each row
declare
v_id number;
v_sqlcode varchar2(6);
v_sqlerrm varchar2(200);
v_error_comment varchar2(300);
v_trigger_user varchar2(30);
v_trigger_date date;
begin
v_error_comment :='before get user';
v_trigger_user :=user;
v_id :=seq_jz.nextval;
:new.id:=v_id;
:new.log_date :=sysdate ;
:new.who :=user;
v_error_comment :='after get user';
v_trigger_date :=sysdate;
exception
when others then
v_sqlcode :=sqlcode;
v_sqlerrm :=substr(sqlerrm,1,200);
insert into error_trigger(error_no,error_message,trigger_name,trgger_user,trigger_date,error_comment)
values(v_sqlcode,v_sqlerrm,'t1_insert',v_trigger_user,v_trigger_date,v_error_comment);
commit;
end;
/
</span>
为t表添加测试数据(添加2,3月份数据,注意这里2月份是没有29号以后的日期的):
<span style="font-family:Verdana;font-size:18px;">declare
v_num varchar2(30);
begin
for i in 1..31 loop
v_num :=i;
if v_num<=9 then
v_num :='0'||v_num;
end if;
insert into t values(v_num,'2016-03-'||v_num) ;
end loop;
commit;
end;
/</span>
<span style="font-family:Verdana;font-size:18px;">create or replace procedure test_loop is
v_count number :=0;
v_num number :=0;
begin
for x in (select id,to_date(month,'yyyy-mm-dd') month from t)
loop
begin
insert into t2 values(x.id,x.month);
v_count :=v_count+1;
v_num :=v_num+1;
if v_count>29 then
commit;
v_count:=0;
end if;
exception
when others then
error_insert('内部第'||v_num||'条数据插入错误 '||sqlerrm);
end ;
end loop;
commit;
exception
when others then
error_insert('外部第'||v_num||'条数据插入错误 '||sqlerrm);
end;
/
</span>
报错存储过程:
create or replace procedure error_insert(p_log_context varchar2) is
pragma autonomous_transaction;
begin
insert into t1(log_context) values(p_log_context);
commit;
end;
/
结果集用截图说明: 在处理到29条数据时,由于无效日期原因,捕获异常后,过程停止,即使之后还有正常数据,异常处理后并没有继续处理正常的数据!
笔者在代码圈定处理数据的时候加入了排序:
<span style="font-family:Verdana;font-size:18px;">for x in (select id,to_date(month,'yyyy-mm-dd') month from t order by 1)
</span>
<span style="font-family:Verdana;font-size:18px;"> 这个圈定数据根本不会出来结果集,因为会报错,但是之前不加排序,是可以显示2016-02-30之前的数据的,缓存到这一条才会报错,之前的数据都可以处理,这就跟oracle的返回机制有关系了,这个还请大神给予解读!</span>
<span style="font-family:Verdana;font-size:18px;"><img src="https://img-blog.youkuaiyun.com/20160917220427960?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
</span>