oracle for循环loop的工作机制

本文探讨了Oracle中FOR LOOP循环的工作原理,通过构建测试用例分析了其是在获取完整结果集后再处理还是在循环过程中逐条处理数据。同时,提到了在处理数据时遇到的排序问题和创建测试用表及填充数据的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构建测试用例的思路是: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>





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值