介紹兩種遊標cursor與sys_refcursor

風靈使發表於2018-04-17

1、cursor遊標使用

    /*簡單cursor遊標  
     *students表裡面有name欄位,你可以換做其他表測試  
     */  
    --定義   
    declare  
     --定義遊標並且賦值(is 不能和cursor分開使用)   
     cursor stus_cur is select * from students;  
     --定義rowtype   
     cur_stu students%rowtype;  
     /*開始執行*/  
     begin  
       --開啟遊標   
       open stus_cur;  
          --loop迴圈   
          loop   
            --迴圈條件   
            exit when stus_cur%notfound;  
            --遊標值賦值到rowtype   
            fetch stus_cur into cur_stu;  
            --輸出   
            dbms_output.put_line(cur_stu.name);  
          --結束迴圈     
          end loop;  
        --關閉遊標     
       close stus_cur;  
      /*結束執行*/  
     end;      

執行結果

    SQL> declare  
      2   --定義遊標並且賦值(is 不能和cursor分開使用)   
      3   cursor stus_cur is select * from students;  
      4   --定義rowtype   
      5   cur_stu students%rowtype;  
      6   /*開始執行*/  
      7   begin  
      8     --開啟遊標   
      9     open stus_cur;  
     10        --loop迴圈   
     11        loop  
     12          --迴圈條件   
     13          exit when stus_cur%notfound;  
     14          --遊標值賦值到rowtype   
     15          fetch stus_cur into cur_stu;  
     16          --輸出   
     17          dbms_output.put_line(cur_stu.name);  
     18        --結束迴圈   
     19        end loop;  
     20      --關閉遊標   
     21     close stus_cur;  
     22    /*結束執行*/  
     23   end;  
     24  /  

    楊過  
    郭靖  
    付政委  
    劉自飛  
    江風  
    任我行  
    任盈盈  
    令狐沖  
    韋一笑  
    張無忌  
    朵兒  
    謝遜  
    小龍女  
    歐陽鋒  
    歐陽鋒  

2、sys_refcursor遊標使用

    /*  
     *遊標名:sys_refcursor  
     *特別注意賦值方式:for  
     *與上重複內容不在敘述  
     */  
    declare  
       stu_cur sys_refcursor;  
       stuone students%rowtype;  

       begin  
         --這句賦值方式for   
         open stu_cur for select * from students;  
         --fetch賦值給rowtype   
         fetch stu_cur into stuone;  

         loop   
           dbms_output.put_line(stuone.name||' '||stuone.hobby);  
           fetch stu_cur into stuone;  
           exit when stu_cur%notfound;  
         end loop;  
       end;  

執行結果

    SQL> /*  
      2   *遊標名:sys_refcursor  
      3   *特別注意賦值方式:for  
      4   *與上重複內容不在敘述  
      5   */  
      6  declare  
      7     stu_cur sys_refcursor;  
      8     stuone students%rowtype;  
      9    
     10     begin  
     11       --這句賦值方式for   
     12       open stu_cur for select * from students;  
     13       --fetch賦值給rowtype   
     14       fetch stu_cur into stuone;  
     15    
     16       loop  
     17         dbms_output.put_line(stuone.name||' '||stuone.hobby);  
     18         fetch stu_cur into stuone;  
     19         exit when stu_cur%notfound;  
     20       end loop;  
     21     end;  
     22  /  

    楊過 保護小龍女  
    郭靖 修煉降龍十八掌  
    付政委 看小人書  
    劉自飛 程式設計寫程式碼  
    江風 程式設計寫程式碼  
    任我行 修煉神功  
    任盈盈 遊山玩水  
    令狐沖 行俠仗義  
    韋一笑 吸拾人雪  
    張無忌 修行  
    朵兒 洗浴  
    謝遜 畢生研究屠龍刀  
    小龍女 修煉玉女心經  
    歐陽鋒 看小人書  

補充一種迴圈條件

    declare  

       stu_cur sys_refcursor;  
       stuone students%rowtype;  

       begin  
         open stu_cur for select * from students;  
         fetch stu_cur into stuone;  
         --特別注意迴圈條件的改變   
         --這個條件是發現了在迴圈   
         --與上一個notfound不同的   
         while stu_cur%found loop   
           dbms_output.put_line(stuone.name||' '||stuone.hobby);  
           fetch stu_cur into stuone;  
         end loop;  
       end;  

oracle中REF Cursor用法

1,什麼是 REF遊標 ?

動態關聯結果集的臨時物件。即在執行的時候動態決定執行查詢。

2,REF 遊標 有什麼作用?

實現在程式間傳遞結果集的功能,利用REF CURSOR也可以實現BULK SQL,從而提高SQL效能。

3,靜態遊標和REF 遊標的區別是什麼?

①靜態遊標是靜態定義,REF 遊標是動態關聯;
②使用REF 遊標需REF 遊標變數。
③REF 遊標能做為引數進行傳遞,而靜態遊標是不可能的。

4,什麼是REF 遊標變數?

REF遊標變數是一種 引用 REF遊標型別 的變數,指向動態關聯的結果集。

5,怎麼使用 REF遊標 ?

①宣告REF 遊標型別,確定REF 遊標型別;
⑴強型別REF遊標:指定retrun type,REF 遊標變數的型別必須和return type一致。
語法:Type REF遊標名 IS Ref Cursor Return 結果集返回記錄型別;
⑵弱型別REF遊標:不指定return type,能和任何型別的CURSOR變數匹配,用於獲取任何結果集。
語法:Type REF遊標名 IS Ref Cursor;

②宣告Ref 遊標型別變數;
語法:變數名 已宣告Ref 遊標型別;

③開啟REF遊標,關聯結果集 ;
語法:Open Ref 遊標型別變數 For 查詢語句返回結果集;

④獲取記錄,操作記錄;
語法:Fatch REF遊標名 InTo 臨時記錄型別變數或屬性型別變數列表;

⑤關閉遊標,完全釋放資源;
語法:Close REF遊標名;

例子:強型別REF遊標

程式碼如下

 /*conn scott/tiger*/
 Declare 
  Type MyRefCurA IS  REF CURSOR RETURN emp%RowType;
  Type MyRefCurB IS  REF CURSOR RETURN emp.ename%Type;
  vRefCurA  MyRefCurA;
  vRefCurB  MyRefCurB;
  vTempA  vRefCurA%RowType;
  vTempB  vRefCurB.ename%Type;

 Begin
  Open  vRefCurA  For Select  *  from   emp   Where  SAL > 2000;
  Loop
   Fatch  vRefCurA InTo  vTempA;
   Exit  When  vRefCurA%NotFound;
   DBMS_OUTPUT.PUT_LINE(vRefCurA%RowCount||'  '|| vTempA.eno||'  '||vTempA.ename ||'  '||vTempA.sal)
  End Loop;
  Close vRefCurA;

  DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------------------------------------------');

  Open  vRefCurB  For Select  ename  from   emp   Where  SAL > 2000;
  Loop
   Fatch  vRefCurB InTo  vTempB;
   Exit  When  vRefCurB%NotFound;
   DBMS_OUTPUT.PUT_LINE(vRefCurB%RowCount||'  '||vTempB)
  End Loop;
  Close vRefCurB; 

  DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------------------------------------------');   

  Open  vRefCurA  For Select  *  from   emp   Where  JOB = 'CLERK';
  Loop
   Fatch  vRefCurA InTo  vTempA;
   Exit  When  vRefCurA%NotFound;
   DBMS_OUTPUT.PUT_LINE(vRefCurA%RowCount||'  '|| vTempA.eno||'  '||vTempA.ename ||'  '||vTempA.sal)
  End Loop;
  Close vRefCurA;
 End;

例子:弱型別REF遊標

程式碼如下

/*conn scott/tiger*/
 Declare
  Type MyRefCur  IS  Ref  Cursor;
  vRefCur MyRefCur;
  vtemp  vRefCur%RowType;
 Begin
  Case(&n)
   When  1 Then Open vRefCur  For Select   *   from emp;
   When  2 Then Open vRefCur  For Select   *   from dept;
   Else 
    Open vRefCur  For Select   eno,  ename  from emp Where JOB = 'CLERK';
  End Case;
  Close  vRefCur;
 End;

6,怎樣讓REF遊標作為引數傳遞?

程式碼如下

--作為函式返回值
create or replace function returnacursor return sys_refcursor 
is
   v_csr sys_refcursor;
begin
    open v_csr for select a1 from test3;
    return v_csr;
end;
/

declare
c sys_refcursor;
a1 char(2);
begin
  c:=returnacursor;
  loop
    fetch c into a1;
    exit when c%notfound;
    dbms_output.put_line(a1);
  end loop;
  close c;
end;
/

--作為引數
create or replace procedure proc_ref_cursor (rc in sys_refcursor) as
  v_a number;
  v_b varchar2(10);

begin
  loop
    fetch rc into v_a, v_b;
    exit when rc%notfound;
    dbms_output.put_line(v_a || ' ' || v_b);
  end loop;
end;
/

declare
v_rc sys_refcursor;
begin
  open v_rc for 
  select a1,a2 from test3;
  proc_ref_cursor(v_rc);
  close v_rc;
end;
/

REF CURSOR 示例包括下列三個 Visual Basic 示例,演示如何使用 REF CURSOR。

示例 說明
OracleDataReader 中檢索 REF CURSOR 引數
此示例執行一個 PL/SQL 儲存過程,返回 REF CURSOR 引數,並將值作為 OracleDataReader 讀取。

使用 OracleDataReader 從多個 REF CURSOR 檢索資料
此示例執行一個 PL/SQL 儲存過程,返回兩個 REF CURSOR 引數,並使用 OracleDataReader 讀取值。

使用一個或多個 REF CURSOR 填充 DataSet
此示例執行一個 PL/SQL 儲存過程,返回兩個 REF CURSOR 引數,並使用返回的行填充 DataSet

要使用這些示例,可能需要建立 Oracle 表,並且必須建立 PL/SQL 包和包正文。

建立 Oracle 表
這些示例使用 Oracle Scott/Tiger 架構中定義的表。大多數 Oracle 安裝均包括 Oracle Scott/Tiger 架構。如果此架構不存在,可以使用 {OracleHome}rdbmsadminscott.sql 中的 SQL 命令檔案建立供這些示例使用的表和索引。

建立 Oracle 包和包正文
這些示例要求伺服器上存在以下 PL/SQL 包和包正文。在 Oracle 伺服器上建立以下 Oracle 包

程式碼如下

CREATE OR REPLACE PACKAGE BODY CURSPKG AS
    PROCEDURE OPEN_ONE_CURSOR (N_EMPNO IN NUMBER,
                               IO_CURSOR IN OUT T_CURSOR)
    IS 
        V_CURSOR T_CURSOR; 
    BEGIN 
        IF N_EMPNO <> 0 
        THEN
             OPEN V_CURSOR FOR 
             SELECT EMP.EMPNO, EMP.ENAME, DEPT.DEPTNO, DEPT.DNAME 
                  FROM EMP, DEPT 
                  WHERE EMP.DEPTNO = DEPT.DEPTNO 
                  AND EMP.EMPNO = N_EMPNO;

        ELSE 
             OPEN V_CURSOR FOR 
             SELECT EMP.EMPNO, EMP.ENAME, DEPT.DEPTNO, DEPT.DNAME 
                  FROM EMP, DEPT 
                  WHERE EMP.DEPTNO = DEPT.DEPTNO;

        END IF;
        IO_CURSOR := V_CURSOR; 
    END OPEN_ONE_CURSOR;

    PROCEDURE OPEN_TWO_CURSORS (EMPCURSOR OUT T_CURSOR,
                                DEPTCURSOR OUT T_CURSOR)
    IS 
        V_CURSOR1 T_CURSOR; 
        V_CURSOR2 T_CURSOR; 
    BEGIN 
        OPEN V_CURSOR1 FOR SELECT * FROM EMP;
        OPEN V_CURSOR2 FOR SELECT * FROM DEPT;
        EMPCURSOR  := V_CURSOR1; 
        DEPTCURSOR := V_CURSOR2; 
    END OPEN_TWO_CURSORS; 
END CURSPKG;
/

Oracle提供REF CURSOR,通過該功能可以實現在程式間傳遞結果集的功能,利用REF CURSOR也可以實現BULK SQL,從而提高SQL效能。

使用scott使用者的emp表實現以下測試案例:

程式碼如下

SQL> desc emp
Name Null? Type
----------------------------------------- -------- ----------------------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)

使用ref cursor獲得結果集輸出:


SQL> set serveroutput on
SQL> DECLARE
2 TYPE mytable IS TABLE OF emp%ROWTYPE;
3 l_data mytable;
4 l_refc sys_refcursor;
5 BEGIN
6 OPEN l_refc FOR
7 SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM emp;
8 
9 FETCH l_refc BULK COLLECT INTO l_data;
10 
11 CLOSE l_refc;
12 
13 FOR i IN 1 .. l_data.COUNT
14 LOOP
15 DBMS_OUTPUT.put_line ( l_data (i).ename
16 || ' was hired since '
17 || l_data (i).hiredate
18 );
19 END LOOP;
20 END;
21 /
SMITH was hired since 17-DEC-80
ALLEN was hired since 20-FEB-81
WARD was hired since 22-FEB-81
JONES was hired since 02-APR-81
MARTIN was hired since 28-SEP-81
BLAKE was hired since 01-MAY-81
CLARK was hired since 09-JUN-81
SCOTT was hired since 19-APR-87
KING was hired since 17-NOV-81
TURNER was hired since 08-SEP-81
ADAMS was hired since 23-MAY-87
JAMES was hired since 03-DEC-81
FORD was hired since 03-DEC-81
MILLER was hired since 23-JAN-82

PL/SQL procedure successfully completed.


-The End-

相關文章