【开发篇plsql】plsql游标

4,游标

经典的数据库编程中,用来处理返回一个查询结果时使用的内部数据结构叫做游标。

Plsql的游标可以分为隐式游标和显式游标。

显式游标由用户显式声明,游标将指向活动集中的当前行,可以显式的打开,提取,关闭。例如:

SQL> declare

  2    cursor cur_emp is

  3      select * from scott.emp;

  4    v_emp scott.emp%rowtype;

  5  begin

  6    open cur_emp;

  7    fetch cur_emp

  8      into v_emp;

  9    DBMS_output.put_line('empno: ' || v_emp.empno || ' ename: ' ||

 10                         v_emp.ename);

 11    close cur_emp;

 12  end;

 13  /

 

PL/SQL procedure successfully completed

 

或者也可以使用for loop 的形式来打开和使用游标:

SQL> declare

  2    cursor cur_emp is

  3      select * from scott.emp where rownum = 1;

  4    v_emp scott.emp%rowtype;

  5  begin

  6    for cs in cur_emp loop

  7        dbms_output.put_line('cs.empno:'||cs.empno);

  8    end loop;

  9  end;

 10  /

 

PL/SQL procedure successfully completed

 

也可以嵌套定义游标

SQL> declare

  2    cursor cur_emp is

  3      select * from scott.emp a where a.empno = 7369;

  4 

  5    cursor cur_emp_1 is

  6      select cursor (select * from scott.emp a where a.empno = 7369)

  7        from scott.emp a where rownum <4;

  8    cur_type sys_refcursor;

  9    v_emp    scott.emp%rowtype;

 10 

 11  begin

 12    open cur_emp_1;

 13 

 14    loop

 15      fetch cur_emp_1

 16        into cur_type;

 17      exit when cur_emp_1%notfound;

 18      dbms_output.put_line('begin outer loop:');

 19      loop

 20        fetch cur_type

 21          into v_emp;

 22        exit when cur_type%notfound;

 23        dbms_output.put_line('begin inner loop:');

 24        dbms_output.put_line(v_emp.empno);

 25      end loop;

 26    end loop;

 27    close cur_emp_1;

 28  end;

 29  /

 

begin outer loop:

begin inner loop:

7369

begin outer loop:

begin inner loop:

7369

begin outer loop:

begin inner loop:

7369

 

PL/SQL procedure successfully completed

 

游标属性

注意到上述的

exit when cur_emp_1%notfound;

这里是循环退出的条件, notfound是游标的属性之一,plsql提供了几个游标属性:

名称

描述

%FOUND

记录成功提取,返回true,否则返回false

%NOTFOUND

记录没有成功提取,返回true,否则返回false

%ROWCOUNT

当前从游标中提取的记录数量

%ISOPEN

游标是否已经打开

%BULK_ROWCOUNT

返回由forall修改了的记录数量

%BULK_EXCEPTIONS

返回forall语句修改后的行的例外信息

%BULK_ROWCOUNT%BULK_EXCEPTIONS这两个属性在批量处理中示意。

 

 

 

隐式游标

Plsql在每次执行一个DML语句(insert,update,delete)或者使用select into从数据库中直接返回单行到plsql数据库结构中是,都会定义和操纵一个隐式游标。

之所以称做隐式,是因为oracle自动的管理游标相关的操作,比如分配一个游标,打开一个游标,

提取记录,乃至关闭游标。例如:

SQL> declare

  2    v_emp scott.emp%rowtype;

  3    i     number := 0;

  4  begin

  5    for cur_emp in (select * from scott.emp where rownum = 1) loop

  6      DBMS_output.put_line(i);

  7    end loop;

  8  end;

  9  /

 

PL/SQL procedure successfully completed

 

游标变量

可以在数据库中声明一个游标的引用变量,可以在运行时赋值或者改变。

同时可以将游标变量作为函数或者过程的参数,当需要传递结果集到其他环境(比较java)的时候,这种用法很有用。

声明的游标变量可以定义返回类型(强类型)或者不定义返回类型(弱类型),示例:

SQL> declare

  2    v_emp scott.emp%rowtype;

  3    type t_cur_emp_str is ref cursor return scott.emp%rowtype;

  4    v_cur_emp_str t_cur_emp_str;

  5    type t_cur_emp_weak is ref cursor;

  6    v_cur_emp_weak t_cur_emp_weak;

  7 

  8  begin

  9    open v_cur_emp_str for

 10      select * from scott.emp where rownum = 1;

 11 

 12    fetch v_cur_emp_str

 13      into v_emp;

 14 

 15    close v_cur_emp_str;

 16 

 17    open v_cur_emp_weak for

 18      select * from scott.emp where rownum = 1;

 19 

 20    fetch v_cur_emp_weak

 21      into v_emp;

 22    close v_cur_emp_weak;

 23  end;

 24  /

 

PL/SQL procedure successfully completed

 

 

或者用来作为函数或者存储过程的参数

SQL> declare

  2    type tp_cur_emp_str is ref cursor return scott.emp%rowtype;

  3    cur_emp_str tp_cur_emp_str;

  4    v_emp_row   scott.emp%rowtype;

  5 

  6    function func_use_cur(cur in tp_cur_emp_str) return number is

  7      v_emprow scott.emp%rowtype;

  8      num      number := 0;

  9    begin

 10      loop

 11        fetch cur

 12          into v_emprow;

 13        exit when cur%notfound;

 14        num := cur%rowcount;

 15      end loop;

 16      return num;

 17    end;

 18 

 19    procedure proc_use_cur(cur in tp_cur_emp_str) is

 20      v_emprow scott.emp%rowtype;

 21    begin

 22      loop

 23        fetch cur

 24          into v_emprow;

 25        exit when cur%notfound;

 26        dbms_output.put_line('cur%rowcount :' || cur%rowcount);

 27        dbms_output.put_line('v_emprow.empno:' || v_emprow.empno);

 28      end loop;

 29    end;

 30 

 31  begin

 32    open cur_emp_str for

 33      select * from scott.emp a where rownum < 5;

 34    dbms_output.put_line('func_use_cur(cur_emp_str): ' ||

 35                         func_use_cur(cur_emp_str)||chr(10));

 36    close cur_emp_str;

 37 

 38    open cur_emp_str for

 39      select * from scott.emp a where rownum < 5;

 40    proc_use_cur(cur_emp_str);

 41    close cur_emp_str;

 42 

 43  end;

 44  /

 

func_use_cur(cur_emp_str): 4

 

cur%rowcount :1

v_emprow.empno:1

cur%rowcount :2

v_emprow.empno:7369

cur%rowcount :3

v_emprow.empno:7499

cur%rowcount :4

v_emprow.empno:7521

 

PL/SQL procedure successfully completed

 

也可以用作函数的返回值,或者函数和存储过程的out 参数,或者结合管道函数方面的使用,在过程和函数小结时再具体举例。

 

可以使用 where current of更新游标中当前行如:

SQL> declare

  2    cursor cs is

  3      select * from scott.emp a where a.empno = 1 for update;

  4  begin

  5    for css in cs loop

  6      update scott.emp a set a.ename = 'ename' where current of cs;

  7    end loop;

  8  end;

  9  /

 

PL/SQL procedure successfully completed

 

再来看看使用显式游标与select into的隐式游标在读取一行时的比较,可以看出单行读取的情况下好像隐式游标稍稍好一点:

SQL> set timi on;

SQL> declare

  2    cursor cs is

  3      select dummy from dual;

  4    v_dummy dual.dummy%type;

  5  begin

  6    for i in 1 .. 100000 loop

  7      open cs;

  8      fetch cs

  9        into v_dummy;

 10      close cs;

 11    end loop;

 12  end;

 13  /

 

PL/SQL procedure successfully completed

 

Executed in 4.141 seconds

 

SQL>

SQL> declare

  2    v_dummy dual.dummy%type;

  3  begin

  4    for i in 1 .. 100000 loop

  5      select dummy into v_dummy from dual;

  6    end loop;

  7  end;

  8  /

 

PL/SQL procedure successfully completed

 

Executed in 3.172 seconds

很多时候把操作尽可能的让oracle来做效果要好一点。

如果上面一个不明显的话,再看一个含有order bycursor的例子:

create table t_test_cusor as select * from all_objects a ;

/

 

SQL> select count(*) from all_objects a ;

 

  COUNT(*)

----------

     59069

 

Executed in 3.265 seconds

 

SQL> declare

  2    cursor cs is

  3      select object_name from t_test_cusor a order by object_id desc;

  4    v_object_name t_test_cusor.object_name%type;

  5  begin

  6    for i in 1 .. 500 loop

  7      open cs;

  8      fetch cs

  9        into v_object_name;

 10      close cs;

 11    end loop;

 12  end;

 13  /

 

PL/SQL procedure successfully completed

 

Executed in 19.954 seconds

 

SQL> declare

  2    v_object_name t_test_cusor.object_name%type;

  3  begin

  4    for i in 1 .. 500 loop

  5      select object_name

  6        into v_object_name

  7        from (select object_name from t_test_cusor order by object_id desc)

  8       where rownum = 1;

  9    end loop;

 10  end;

 11  /

 

PL/SQL procedure successfully completed

 

Executed in 11.532 seconds

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16179598/viewspace-664455/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/16179598/viewspace-664455/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值