oracle的PL/SQL中关于游标的notfound属性分析

一、问题起源:

       在看马老师的Oracle - PL/SQL视频的"游标"部分时, 讲到如何用遍历输出一个结果集时,有个这样的代码例子.

 declare
     cursor c is
	      select * from emp;
     v_emp c%rowtype;
   begin
     open c;	
     loop
       fetch c into v_emp;
       exit when (c%notfound);
            dbms_output.put_line(v_emp.ename); 
    end loop;
    close c;
   end;


   并且强调:  fetch c into v_emp; 一定要放在  exit when (c%notfound); 前面才行. 不然会把最后一条记录多输出一遍. 


二 、我的疑惑,
(1)为什么exit when放在fetch前面会多输出一条记录?
exit when在fetch前面的话,不是在最后一次fetch到有效记录后,游标自动跳到下一个位置,没有指向一个有效记录,此时notfound的值为true,在下次进行exit when((c%notfound)判断时不是因为true自动退出循环吗?怎么会继续去执行循环体下面的输出代码呢?
(2)notfound属性的值真的是取决于游标的当前是否指向一条有效记录吗?还是取决于fetch数据的结果?
(3)同时对游标这个概念的也不知如何理解?


三、分析问题找疑惑根源并做针对性的相关测试解惑
发现就这个问题而言,最核心的疑惑来自于对notfound这个游标的属性值到底是怎么取决于什么没弄清楚,是fetch前后产生变化还是和游标状态什么的相关?决定写一些辅助的输出notfound在fetch前后的值。测试代码
(1)exit-when在fetch前面

declare
    cursor c is
      select * from emp;
    v_emp c%rowtype;
    v_tmp number(6) :=0;
begin
    open c;  
    loop
           v_tmp := v_tmp+1;
           dbms_output.put_line('_________________'||v_tmp);
      exit when (c%notfound);
        if((c%notfound)=true) then
            dbms_output.put_line('exit-when后-fetch前,notfound值为-真');
        elsif((c%notfound)=false) then
            dbms_output.put_line('exit-when后-fetch前,notfound值为-假');
        else
            dbms_output.put_line('exit-when后-fetch前,notfound值为-空');
        end if;
      fetch c into v_emp;
       dbms_output.put_line(v_emp.ename||'********');
          if((c%notfound)=true) then
             dbms_output.put_line('fetch后notfound值为-真');
          elsif((c%notfound)=false) then
             dbms_output.put_line('fetch后notfound值为-假');
          else
             dbms_output.put_line('fetch后notfound值为-空');
          end if;
       dbms_output.put_line('_________________'||v_tmp);
    end loop;
    close c;
end;

运行结果是

_________________1
exit-when后-fetch前,notfound值为-空
SMITH********
fetch后notfound值为-假
_________________1
_________________2
exit-when后-fetch前,notfound值为-假
ALLEN********
fetch后notfound值为-假
_________________2
_________________3
exit-when后-fetch前,notfound值为-假
WARD********
fetch后notfound值为-假
_________________3
_________________4
exit-when后-fetch前,notfound值为-假
JONES********
fetch后notfound值为-假
_________________4
_________________5
exit-when后-fetch前,notfound值为-假
MARTIN********
fetch后notfound值为-假
_________________5
_________________6
exit-when后-fetch前,notfound值为-假
BLAKE********
fetch后notfound值为-假
_________________6
_________________7
exit-when后-fetch前,notfound值为-假
CLARK********
fetch后notfound值为-假
_________________7
_________________8
exit-when后-fetch前,notfound值为-假
SCOTT********
fetch后notfound值为-假
_________________8
_________________9
exit-when后-fetch前,notfound值为-假
KING********
fetch后notfound值为-假
_________________9
_________________10
exit-when后-fetch前,notfound值为-假
TURNER********
fetch后notfound值为-假
_________________10
_________________11
exit-when后-fetch前,notfound值为-假
ADAMS********
fetch后notfound值为-假
_________________11
_________________12
exit-when后-fetch前,notfound值为-假
JAMES********
fetch后notfound值为-假
_________________12
_________________13
exit-when后-fetch前,notfound值为-假
FORD********
fetch后notfound值为-假
_________________13
_________________14
exit-when后-fetch前,notfound值为-假
MILLER********
fetch后notfound值为-假
_________________14
_________________15
exit-when后-fetch前,notfound值为-假
MILLER********
fetch后notfound值为-真
_________________15
_________________16

(2)fetch在exit when前面

declare
    cursor c is
           select * from emp;
    v_emp c%rowtype;
    v_tmp number(6) :=0;
begin
    open c;  
    loop
            v_tmp := v_tmp+1;
            dbms_output.put_line('___________'||v_tmp||'___________');
        if((c%notfound)=true) then
           dbms_output.put_line('notfound值为--真___fetch前');
        elsif((c%notfound)=false) then
           dbms_output.put_line('notfound值为--假___fetch前');
        else
           dbms_output.put_line('notfound值为--空___fetch前');
        end if;
     fetch c into v_emp;
        if((c%notfound)=true) then
           dbms_output.put_line('notfound值为--真___fetch后exit-when前');
        elsif((c%notfound)=false) then
           dbms_output.put_line('notfound值为--假___fetch后exit-when前');
        else
           dbms_output.put_line('notfound值为--空___fetch后exit-when前');
        end if;
     exit when (c%notfound);
      dbms_output.put_line(v_emp.ename||'********'); 
         if((c%notfound)=true) then
            dbms_output.put_line('notfound值为--真___exit-when判定后');
         elsif((c%notfound)=false) then
            dbms_output.put_line('notfound值为--假___exit-when判定后');
         else
            dbms_output.put_line('notfound值为--空___exit-when判定后');
         end if;
      dbms_output.put_line('___________'||v_tmp||'___________');
    end loop;
    close c;
end;

运行结果是

___________1___________
notfound值为--空___fetch前
notfound值为--假___fetch后exit-when前
SMITH********
notfound值为--假___exit-when判定后
___________1___________
___________2___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
ALLEN********
notfound值为--假___exit-when判定后
___________2___________
___________3___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
WARD********
notfound值为--假___exit-when判定后
___________3___________
___________4___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
JONES********
notfound值为--假___exit-when判定后
___________4___________
___________5___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
MARTIN********
notfound值为--假___exit-when判定后
___________5___________
___________6___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
BLAKE********
notfound值为--假___exit-when判定后
___________6___________
___________7___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
CLARK********
notfound值为--假___exit-when判定后
___________7___________
___________8___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
SCOTT********
notfound值为--假___exit-when判定后
___________8___________
___________9___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
KING********
notfound值为--假___exit-when判定后
___________9___________
___________10___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
TURNER********
notfound值为--假___exit-when判定后
___________10___________
___________11___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
ADAMS********
notfound值为--假___exit-when判定后
___________11___________
___________12___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
JAMES********
notfound值为--假___exit-when判定后
___________12___________
___________13___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
FORD********
notfound值为--假___exit-when判定后
___________13___________
___________14___________
notfound值为--假___fetch前
notfound值为--假___fetch后exit-when前
MILLER********
notfound值为--假___exit-when判定后
___________14___________
___________15___________
notfound值为--假___fetch前
notfound值为--真___fetch后exit-when前


四、解惑总结
(1)游标的notfound属性值取决于fetch的结果,而非取决于游标当前是否指向一条有效记录。notfound并不是表示当前游标是不是指向一条有效记录。
(2)对于显式游标而言,open后第一次fetch之前cursor%notfound的值为null。中间所有能fetch到记录的情况的fetch前后cursor%notfound的值均为false。直到最后一次fetch但是fetch不到记录了值就为true了。
(3)注意的一点,pl/sql中的boolean类型变量还有个null值,并且还是默认的.除此之外还有true,false.









评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值