oracle cursor学习(转摘)

本文深入探讨Oracle中的游标使用方法,包括基本的CURSOR声明、打开、读取、关闭过程,以及FOR循环中的自动管理。并通过多个测试示例,如test_cursor1、test_cursor2等,对比不同场景下游标的特性及注意事项。

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

oracle cursor学习

/** 测试语句1 */
create or replace procedure test_cursor1 as

          cursor c1 is select * from procedure_test;
          id procedure_test.id%type;
          v1 procedure_test.value1%type;
          v2 procedure_test.value2%type;
          v3 procedure_test.value3%type;
          v4 procedure_test.value4%type;

begin
        open c1;
     
        loop
            fetch c1 into id, v1, v2, v3, v4;
            dbms_output.put_line( 'id=' || id || ' v1=' || v1 || ' v2=' || v2 || ' v3=' || v3 || ' v4=' || v4 );
            exit when c1%notfound;
        end loop;
     
        close c1;
end;

/** 数据
1 1000 a 1000 a
2 1001 b 1001 b
3 1002 c 1002 c
4 1003 d 1003 d
5 1004 e 1004 e
6 1005 f 1005 f
7 1006 g 1006 g
*/

/** 输出
id=1 v1=1000 v2=a v3=1000 v4=a
id=2 v1=1001 v2=b v3=1001 v4=b
id=3 v1=1002 v2=c v3=1002 v4=c
id=4 v1=1003 v2=d v3=1003 v4=d
id=5 v1=1004 v2=e v3=1004 v4=e
id=6 v1=1005 v2=f v3=1005 v4=f
id=7 v1=1006 v2=g v3=1006 v4=g
id=7 v1=1006 v2=g v3=1006 v4=g
*/

/** 测试心得
结合例子revert_date来看,可以发现用for循环来访问游标时,游标是
自动打开和关闭的,但使用loop -- exit -- end loop组和的时候必须
手动打开游标和关闭游标,并且游标的移动也是通过fetch来手动控制
的*/

/** 测试语句2 */
create or replace procedure test_cursor2 as

          cursor c1 is select * from procedure_test;
          id procedure_test.id%type;
          v1 procedure_test.value1%type;
          v2 procedure_test.value2%type;
          v3 procedure_test.value3%type;
          v4 procedure_test.value4%type;

begin

        /** 在这里访问cursor的found属性是非法的 */
        --if c1%found then
        --      dbms_output.put_line( 'befor open cursor is open!' );
        --else
        --       dbms_output.put_line( 'befor open cursor is close!' );
        --end if;
     
        open c1;
     
        if c1%found then
           dbms_output.put_line( 'after open cursor is open!' );
        else
            dbms_output.put_line( 'after open cursor is close!' );
        end if;
     
        while c1%found loop
            fetch c1 into id, v1, v2, v3, v4;
            dbms_output.put_line( 'id=' || id || ' v1=' || v1 || ' v2=' || v2 || ' v3=' || v3 || ' v4=' || v4 );
        end loop;
     
        close c1;
     
        /** 在这里访问cursor的found属性也是非法的 */
        --if c1%found then
        --      dbms_output.put_line( 'befor open cursor is open!' );
        --else
        --       dbms_output.put_line( 'befor open cursor is close!' );
        --end if;
     
     
end;

/** 输出
after open cursor is close!
*/

/** 测试心得
在这个例子中使用了cursor的found属性,在open之前和close之后对游标found属性
的访问是非法的。在open之后cursor的found属性仍然为false另外值得注意的是在
fetch之前cursor的found属性是false所以上面这个例子根本没有进入循环,输出为
空。所以用while loop -- end loop 循环来访问cursor必须在进入循环前fetch一
次,这样的写法给人的感觉很不好*/

/** 测试语句3 */
create or replace procedure test_cursor3 as

          cursor c1 is select * from procedure_test for update;
begin
     
        if c1%isopen then
           dbms_output.put_line( 'before enter the for-cycle cursor is open!' );
        else
            dbms_output.put_line( 'before enter the for-cycle cursor is close!' );
        end if;
     
        for cline in c1 loop
            if cline.id = '1' then
               if c1%isopen then
                  dbms_output.put_line( 'aftre enter the for-cycle cursor is auto open!' );
               end if;
            end if;
            dbms_output.put_line( 'id=' || cline.id || ' v1=' || cline.value1 || ' v2=' || cline.value2 || ' v3=' || cline.value3 || ' v4=' || cline.value4 );
            update procedure_test set value1 = 1, value2 = 'a', value3 = 2, value4 = 'b' where current of c1;
            dbms_output.put_line( 'id=' || cline.id || ' v1=' || cline.value1 || ' v2=' || cline.value2 || ' v3=' || cline.value3 || ' v4=' || cline.value4 );
        end loop;
     
        if c1%isopen then
            dbms_output.put_line( 'aftre get out the for-cycle cursor is still open!' );
        else
            dbms_output.put_line( 'aftre get out the for-cycle cursor is auto close!' );
        end if;
     
        commit;
         
end;

/** 运行前
1 1000 a 1000 a
2 1001 b 1001 b
3 1002 c 1002 c
4 1003 d 1003 d
5 1004 e 1004 e
6 1005 f 1005 f
7 1006 g 1006 g
*/

/** 运行后
1 1 a 2 b
2 1 a 2 b
3 1 a 2 b
4 1 a 2 b
5 1 a 2 b
6 1 a 2 b
7 1 a 2 b
*/

/** 输出
before enter the for-cycle cursor is close!
aftre enter the for-cycle cursor is auto open!
id=1 v1=1000 v2=a v3=1000 v4=a
id=1 v1=1000 v2=a v3=1000 v4=a
id=2 v1=1001 v2=b v3=1001 v4=b
id=2 v1=1001 v2=b v3=1001 v4=b
id=3 v1=1002 v2=c v3=1002 v4=c
id=3 v1=1002 v2=c v3=1002 v4=c
id=4 v1=1003 v2=d v3=1003 v4=d
id=4 v1=1003 v2=d v3=1003 v4=d
id=5 v1=1004 v2=e v3=1004 v4=e
id=5 v1=1004 v2=e v3=1004 v4=e
id=6 v1=1005 v2=f v3=1005 v4=f
id=6 v1=1005 v2=f v3=1005 v4=f
id=7 v1=1006 v2=g v3=1006 v4=g
id=7 v1=1006 v2=g v3=1006 v4=g
aftre get out the for-cycle cursor is auto close!
*/

/** 测试心得
这里可以更清楚地看到for循环自动的打开和关闭cursor的过程,而且
可以看到利用游标来更新数据集的写法,只要稍加改变,他们的组合就
可以实现非常强大的功能,就比如在revert_data中实现的那样,值得
注意的是在update后,马上引用,当前行的值并没有改变尝试将语句改
写为test_cursor4的形式看看结果
*/

/** 测试语句4 *
create or replace procedure test_cursor3 as

          cursor c1 is select * from procedure_test for update;
begin
     
        if c1%isopen then
           dbms_output.put_line( 'before enter the for-cycle cursor is open!' );
        else
            dbms_output.put_line( 'before enter the for-cycle cursor is close!' );
        end if;
     
        for cline in c1 loop
            if cline.id = '1' then
               if c1%isopen then
                  dbms_output.put_line( 'aftre enter the for-cycle cursor is auto open!' );
               end if;
            end if;
            dbms_output.put_line( 'id=' || cline.id || ' v1=' || cline.value1 || ' v2=' || cline.value2 || ' v3=' || cline.value3 || ' v4=' || cline.value4 );
            update procedure_test set value1 = 1, value2 = 'a', value3 = 2, value4 = 'b' where current of c1;
            commit;
            dbms_output.put_line( 'id=' || cline.id || ' v1=' || cline.value1 || ' v2=' || cline.value2 || ' v3=' || cline.value3 || ' v4=' || cline.value4 );
         
        end loop;
        
        if c1%isopen then
            dbms_output.put_line( 'aftre get out the for-cycle cursor is still open!' );
        else
            dbms_output.put_line( 'aftre get out the for-cycle cursor is auto close!' );
        end if;
     
        commit;
         
end;

/** 测试结果
在行(for cline in c1 loop)出错,提示违反读取顺序
*/

/** 测试心得
说明在for循环内部不能出现commit语句,for循环有更深的要求
需要查找其他资料
*/

/** 其他说明
当执行一条DML语句后,DML语句的结果保存在四个游标属性中,
这些属性用于控制程序流程或者了解程序的状态。当运行DML语
句时,PL/SQL打开一个内建游标并处理结果,游标是维护查询结
果的内存中的一个区域,游标在运行DML语句时打开,完成后关
闭。隐式游标只使用SQL%FOUND,SQL%NOTFOUND,SQL%ROWCOUNT三个
属性.SQL%FOUND,SQL%NOTFOUND是布尔值,SQL%ROWCOUNT是整数值。
SQL%FOUND和SQL%NOTFOUND在执行任何DML语句前SQL%FOUND和
SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性
值将是:
. TRUE :INSERT
. TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE.
. TRUE :SELECT INTO至少返回一行
当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE。
SQL%ROWCOUNT
在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于
SELECT INTO语句,如果执行成功,SQL%ROWCOUNT的值为1,如果没有
成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND.
SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE, 如果游标关
闭,则为FALSE.对于隐式游标而言SQL%ISOPEN总是FALSE,这是因为
隐式游标在DML语句执行时打开,结束时就立即关闭。
*/

/** 备注
隐式游标将在文件test_hidden_cursor中说明
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值