Oracle 遍歷游標的四種方式匯總(for、fetch、while、BULK COLLECT)


本文原創:https://www.cnblogs.com/Marydon20170307/p/12869692.html 感謝博主分享

注意:原文中方式四FORALL處有語法錯誤,應該使用FOR。

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;  

執行,輸出結果

   變形二:遍歷隱式游標(推薦使用)

  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;
--循環表數據
FOR 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;

注意上面語句的FOR,原為寫成了FORALL是不正確的(我被成功帶到溝里才發現不對)。

 

以下內容出自另一篇博客,更加全面詳細可參考 https://www.cnblogs.com/hellokitty1/p/4584333.html 

DECLARE
   CURSOR emp_cur IS
      SELECT empno, ename, hiredate FROM emp;

   TYPE emp_rec_type IS RECORD
   (
      empno      emp.empno%TYPE,
      ename      emp.ename%TYPE ,
      hiredate   emp.hiredate%TYPE
   );
   -- 定義基於記錄的嵌套表
   TYPE nested_emp_type IS TABLE OF emp_rec_type;
   -- 聲明集合變量
   emp_tab     nested_emp_type;
   -- 定義了一個變量來作為limit的值
   v_limit     PLS_INTEGER := 5;
   -- 定義變量來記錄FETCH次數
   v_counter   PLS_INTEGER := 0;
BEGIN
   OPEN emp_cur;

   LOOP
      -- fetch時使用了BULK COLLECT子句
      FETCH emp_cur
      BULK   COLLECT INTO emp_tab
      LIMIT v_limit; -- 使用limit子句限制提取數據量

      EXIT WHEN emp_tab.COUNT = 0; -- 注意此時游標退出使用了emp_tab.COUNT,而不是emp_cur%notfound
      v_counter   := v_counter + 1;  -- 記錄使用LIMIT之后fetch的次數

      FOR i IN emp_tab.FIRST .. emp_tab.LAST
      LOOP
         DBMS_OUTPUT.PUT_LINE( '當前記錄: '
                    ||emp_tab(i).empno||CHR(9)
                    ||emp_tab(i).ename||CHR(9)
                    ||emp_tab(i).hiredate);
      END LOOP;
   END LOOP;

   CLOSE emp_cur;

   DBMS_OUTPUT.put_line( '總共獲取次數為:' || v_counter );
END;

 

 

 

4.總結

  使用for循環的優勢在於:

  不需要手動打開&關閉游標(聲明游標的開啟和關閉);

  不需要手動捕獲數據(自動將數據fetch到記錄型變量);

  不需要關注何時要退出,也就是不需要寫退出循環的滿足條件(遍歷完成就會退出)。

  第4方式與前3種的區別在於:

  前三種的游標變量:ROW_CUR_FIRST_INDEX,只能存儲游標的一條數據;

  第四種的表變量:TAB_FIRST_INDEX,可以存儲游標的多條數據。

  大數據批量處理的時候,第4種方式的優勢將會凸顯出來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM