zoukankan      html  css  js  c++  java
  • Oracle 遍历游标的四种方式(for、fetch、while、BULK COLLECT)

    1.情景展示

      Oracle 遍历游标的三种方式(for、fetch、while、bulk collect+forall)

    2.问题分析

      我们可以把游标想象成一张表,想要遍历游标,就要取到游标的每行数据,所以问题的关键就成了:如何取到行数据?

    3.解决方案

      方式一:FOR 循环(推荐使用)

      变形一:遍历显式游标

    /* 如果是在存储过程外使用显式游标,需要使用DECLARE关键字 */
    DECLARE
      /*创建游标*/
      CURSOR CUR_FIRST_INDEX IS
        SELECT A.ID        A_ID, --一级指标ID
               A.INDEXNAME A_INDEXNAME --一级指标名称
          FROM INDEX_A A
         ORDER BY A_ID;
      /*定义游标变量,该变量的类型为基于游标CUR_FIRST_INDEX的行记录*/
      ROW_CUR_FIRST_INDEX CUR_FIRST_INDEX%ROWTYPE;
    /*游标处理*/
    BEGIN
      /*遍历显式游标*/
      --FOR 循环
      FOR ROW_CUR_FIRST_INDEX IN CUR_FIRST_INDEX LOOP
        --循环体
        DBMS_OUTPUT.PUT_LINE('{"ID":"' || ROW_CUR_FIRST_INDEX.A_ID || '","名称":"' || ROW_CUR_FIRST_INDEX.A_INDEXNAME || '"}');
      END LOOP;
    END;  

      执行,输出结果

      变形二:遍历隐式游标(推荐使用)

      关于隐式游标的补充:20200519

      for循环遍历游标,其实又可以分为两种方式,一种是显式游标的遍历,另一种是隐式游标的遍历。

    /* 如果是在存储过程外使用隐式游标,如果用不到变量无需声明DECLARE关键字 */
    /*游标处理*/
    BEGIN
      /*遍历隐式游标*/
      --FOR 循环
      FOR ROW_CUR_FIRST_INDEX IN (SELECT A.ID        A_ID, --一级指标ID
                                         A.INDEXNAME A_INDEXNAME --一级指标名称
                                    FROM INDEX_A A
                                   ORDER BY A_ID) LOOP
        --循环体
        DBMS_OUTPUT.PUT_LINE('{"ID":"' || ROW_CUR_FIRST_INDEX.A_ID || '","名称":"' || ROW_CUR_FIRST_INDEX.A_INDEXNAME || '"}');
      END LOOP;
    END;
    

      隐式游标相较于显式游标用法更加简单,无需声明直接调用即可。    

      方式二:FETCH 循环

    /*游标声明代码和方式一一致,此处省略,直接展示游标处理代码*/
    BEGIN
      /*遍历游标*/
      --FETCH 循环
      OPEN CUR_FIRST_INDEX; --必须要明确的打开和关闭游标
      LOOP
        FETCH CUR_FIRST_INDEX INTO ROW_CUR_FIRST_INDEX;
        EXIT WHEN CUR_FIRST_INDEX%NOTFOUND;
        --循环体
        DBMS_OUTPUT.PUT_LINE('{"ID":"' || ROW_CUR_FIRST_INDEX.A_ID || '","名称":"' || ROW_CUR_FIRST_INDEX.A_INDEXNAME || '"}');
      END LOOP;
      CLOSE CUR_FIRST_INDEX;
    END;
    

      

      方式三:WHILE 循环

    /*游标声明代码和方式一一致,此处省略,直接展示游标处理代码*/
    BEGIN
      /*遍历游标*/
      OPEN CUR_FIRST_INDEX; --必须要明确的打开和关闭游标 
      FETCH CUR_FIRST_INDEX
        INTO ROW_CUR_FIRST_INDEX;
      WHILE CUR_FIRST_INDEX%FOUND LOOP
        --循环体 
        DBMS_OUTPUT.PUT_LINE('{"ID":"' || ROW_CUR_FIRST_INDEX.A_ID || '","名称":"' || ROW_CUR_FIRST_INDEX.A_INDEXNAME || '"}');
        FETCH CUR_FIRST_INDEX
          INTO ROW_CUR_FIRST_INDEX;
      END LOOP;
      CLOSE CUR_FIRST_INDEX;
    END;  

      注意:使用while循环时,需要fetch两次。

      方式四:BULK COLLECT+FORALL(速度最快)

    /* 如果是在存储过程外使用显示游标,需要使用DECLARE关键字 */
    /*声明游标*/
    DECLARE
      /*创建显式游标*/
      CURSOR CUR_FIRST_INDEX IS
        SELECT A.ID        A_ID, --一级指标ID
               A.INDEXNAME A_INDEXNAME --一级指标名称
          FROM INDEX_A A
         ORDER BY A_ID;
      /*定义表类型,该表的表结构为游标CUR_FIRST_INDEX的行记录(可以存储多条游标记录)*/
      TYPE TABLE_CUR_FIRST_INDEX IS TABLE OF CUR_FIRST_INDEX%ROWTYPE;
      /* 声明表变量*/
      TAB_FIRST_INDEX TABLE_CUR_FIRST_INDEX;
    /*游标处理过程*/
    BEGIN
      /*遍历游标*/
      OPEN CUR_FIRST_INDEX;
      LOOP
        --将n行游标数据放到表中
        FETCH CUR_FIRST_INDEX BULK COLLECT
          INTO TAB_FIRST_INDEX LIMIT 1; -- 数据量太少,仅当前测试使用哦,实际开发建议 500 左右
        -- 退出条件
        EXIT WHEN TAB_FIRST_INDEX.COUNT = 0;
        --循环表数据
        FORALL I IN TAB_FIRST_INDEX.FIRST .. TAB_FIRST_INDEX.LAST LOOP
          DBMS_OUTPUT.PUT_LINE('{"ID":"' || TAB_FIRST_INDEX(I).A_ID || '","名称":"' || TAB_FIRST_INDEX(I).A_INDEXNAME || '"}');
        END LOOP;
      END LOOP;
      CLOSE CUR_FIRST_INDEX;
    END;
    

        

    4.总结 

      使用for循环的优势在于:

      不需要手动打开&关闭游标(声明游标的开启和关闭);

      不需要手动捕获数据(自动将数据fetch到记录型变量);

      不需要关注何时要退出,也就是不需要写退出循环的满足条件(遍历完成就会退出)。

      第4方式与前3种的区别在于:

      前三种的游标变量:ROW_CUR_FIRST_INDEX,只能存储游标的一条数据;

      第四种的表变量:TAB_FIRST_INDEX,可以存储游标的多条数据。

      大数据批量处理的时候,第4种方式的优势将会凸显出来。

    写在最后

      哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

     相关推荐:

  • 相关阅读:
    15. DML, DDL, LOGON 触发器
    5. 跟踪标记 (Trace Flag) 834, 845 对内存页行为的影响
    4. 跟踪标记 (Trace Flag) 610 对索引组织表(IOT)最小化日志
    14. 类似正则表达式的字符处理问题
    01. SELECT显示和PRINT打印超长的字符
    3. 跟踪标记 (Trace Flag) 1204, 1222 抓取死锁信息
    2. 跟踪标记 (Trace Flag) 3604, 3605 输出DBCC命令结果
    1. 跟踪标记 (Trace Flag) 1117, 1118 文件增长及空间分配方式
    0. 跟踪标记 (Trace Flag) 简介
    SpringBoot + Redis + Shiro 实现权限管理(转)
  • 原文地址:https://www.cnblogs.com/Marydon20170307/p/12869692.html
Copyright © 2011-2022 走看看