Oracle 遍历游标的四种方式(for/fetch/while/BULK COLLECT)

需求理解与分析

Request: 在Oracle中我们可以使用游标Cursor去存储多条查询数据的结果集,现在需要对该结果集的每行数据进行数据操作,即 遍历游标Cursor并针对遍历目标行进行查询操作。如何才能取到游标Cursor的行数据呢?

*本文仅提供查询展示游标数据的四种方式对比,利用游标进行遍历更新、插入等操作的后续会有专文整理。

解决方案

Oracle中对游标Cursor进行遍历的方式有4种 :for | fetch | while | bulk collect + for

方式1: FOR 循环遍历(显示+隐式)

  • 遍历显示游标 
--在存储过程外使用显式游标时,需要使用DECLARE关键字 
DECLARE
  --创建游标
  CURSOR cur_play_info IS
    SELECT A.player_id   AS A_ID        --一级指标ID
          ,A.player_name AS A_INDEXNAME --一级指标名称
      FROM player_info A
     ORDER BY A_ID
  ;
  
  --定义游标变量,该变量的类型为基于游标 cur_play_info 的行记录
  row_cur_play_info cur_play_info%ROWTYPE;
 
BEGIN
  --遍历显示游标
  --设置buffer size
  dbms_output.enable(10000000);
  --FOR 循环
  FOR row_cur_play_info IN cur_play_info LOOP
    --循环体
    DBMS_OUTPUT.PUT_LINE('["玩家ID":"' || row_cur_play_info.A_ID || '","玩家名称":"' || row_cur_play_info.A_INDEXNAME || '"]');
  END LOOP;
END;

        输出结果:数据量1355,耗时0.004s

Oracle 遍历游标的四种方式(for/fetch/while/BULK COLLECT)_第1张图片

  • 遍历隐式游标(无需声明直接调用)
BEGIN
  --遍历显示游标
  --设置buffer size
  dbms_output.enable(10000000);
  --FOR 循环
  FOR row_cur_play_info IN (  SELECT A.player_id   AS A_ID        --一级指标ID
                                    ,A.player_name AS A_INDEXNAME --一级指标名称
                                FROM player_info A
                               ORDER BY A_ID
                           ) LOOP
  --循环体
    DBMS_OUTPUT.PUT_LINE('{"玩家ID":"' || row_cur_play_info.A_ID || '","玩家名称":"' || row_cur_play_info.A_INDEXNAME || '"}');
  END LOOP;
END;

        输出结果同上:数据量1355,耗时0.004s

方式2: FETCH 循环

--FETCH循环
DECLARE
  --创建游标
  CURSOR cur_play_info IS
    SELECT A.player_id   AS A_ID        --一级指标ID
          ,A.player_name AS A_INDEXNAME --一级指标名称
      FROM player_info A
     ORDER BY A_ID
  ;
  
  --定义游标变量,该变量的类型为基于游标 cur_play_info 的行记录
  row_cur_play_info cur_play_info%ROWTYPE;
BEGIN
  
  --打开游标
  OPEN cur_play_info;
  
  LOOP 
    FETCH cur_play_info INTO row_cur_play_info;
  
    --设置停止条件
    EXIT WHEN cur_play_info%NOTFOUND;
    
    --循环体
    DBMS_OUTPUT.PUT_LINE('["玩家ID":"' || row_cur_play_info.A_ID || '","玩家名称":"' || row_cur_play_info.A_INDEXNAME || '"]');
    
  END LOOP;
  
  --关闭游标
  CLOSE cur_play_info;
END;

        输出结果同上:数据量1355,耗时0.015s

方法3:WHILE循环(FECTH两次)

--WHILE循环
DECLARE
  --创建游标
  CURSOR cur_play_info IS
    SELECT A.player_id   AS A_ID        --一级指标ID
          ,A.player_name AS A_INDEXNAME --一级指标名称
      FROM player_info A
     ORDER BY A_ID
  ;
  
  --定义游标变量,该变量的类型为基于游标 cur_play_info 的行记录
  row_cur_play_info cur_play_info%ROWTYPE;
BEGIN
  
  --打开游标
  OPEN cur_play_info;
  
  FETCH cur_play_info INTO row_cur_play_info;
  
  WHILE cur_play_info%FOUND LOOP
    --循环体
    DBMS_OUTPUT.PUT_LINE('["玩家ID":"' || row_cur_play_info.A_ID || '","玩家名称":"' || row_cur_play_info.A_INDEXNAME || '"]');
    
    FETCH cur_play_info INTO row_cur_play_info;
  END LOOP;
  
  --关闭游标
  CLOSE cur_play_info;
END;

        输出结果同上:数据量1355,耗时0.030s

方法4:BULK COLLECT + FOR(速度最快,效率最好)

--BULK COLLECT + FOR循环
DECLARE
  --创建游标
  CURSOR cur_play_info IS
    SELECT A.player_id   AS A_ID        --一级指标ID
          ,A.player_name AS A_INDEXNAME --一级指标名称
      FROM player_info A
     ORDER BY A_ID
  ;
  
  --定义表类型,该表的表结构为游标 cur_play_info 的行记录(存储多条游标数据)
  TYPE table_cur_play_info IS TABLE OF cur_play_info%ROWTYPE;
  
  --声明表变量
  tab_play_info table_cur_play_info;
BEGIN
  
  --打开游标
  OPEN cur_play_info;
  
  LOOP
    --将N行的游标查询数据插入表变量值中
    FETCH cur_play_info BULK COLLECT INTO tab_play_info LIMIT 1355; --由于测试表数据只有1355条,实际开发测试使用更大数据量的表会更具备参考性
  
    --设定退出循环的条件
    EXIT WHEN tab_play_info.COUNT = 0;
    
    --循环输出表变量的数据
    FOR I IN tab_play_info.FIRST .. tab_play_info.LAST LOOP
      DBMS_OUTPUT.PUT_LINE('["玩家ID":"' || tab_play_info(I).A_ID || '","玩家名称":"' || tab_play_info(I).A_INDEXNAME || '"]');
    END LOOP;

  END LOOP;
  
  --关闭游标
  CLOSE cur_play_info;
END;

        输出结果同上:数据量1355,耗时0.004s


四种方式的简要总结如下: 

游标遍历查询
遍历方式 声明游标的开启/关闭 手动捕获(FETCH数据) 遍历退出形式 游标变量 优势
FOR循环 遍历完自动退出 只能存一条数据 写法简洁
FETCH 循环 满足退出条件 只能存一条数据
WHILE循环 满足退出条件 只能存一条数据
BULK COLLECT + FOR 满足退出条件 存多条数据(表变量) 适用于大批量处理数据

若执行测试代码的过程中报错:

Oracle报错/解决:Ora-2000 buffer overflow, limit of 1000 bytes

可以查看:

Oracle报错/解决:Ora-2000 buffer overflow, limit of 1000 bytes_Leona_08051005的博客-CSDN博客icon-default.png?t=L9C2https://blog.csdn.net/qq_39316940/article/details/120805160?spm=1001.2014.3001.5501 

你可能感兴趣的:(ORACLE,oracle,sql,数据库,数据库开发)