1. 程式人生 > >PL/SQL中cursor(游標/遊標)的用法

PL/SQL中cursor(游標/遊標)的用法

顯式cursor

顯式是相對與隱式cursor而言的,就是有一個明確的宣告的cursor.顯式遊標的宣告類似如下(詳細的語法參加plsql ref doc )

cursor cursor_name (parameter list) is select ...

遊標從declare、open、fetch、close是一個完整的生命旅程。當然了一個這樣的遊標是可以被多次open進行使用的,顯式cursor是靜態cursor,她的作用域是全域性的,但也必須明白,靜態cursor也只有pl/sql程式碼才可以使用她。下面看一個簡單的靜態顯式cursor的示例:

declare
            cursor get_gsmno_cur (p_nettype in varchar2) is 
               select gsmno
                  from gsm_resource
                  where nettype=p_nettype and status='0';
             v_gsmno gsm_resource.gsmno%type;
          begin
             open get_gsmno_cur('139');
             loop
                  fetch get_gsmno_cur into v_gsmno;
                  exit when get_gsmno_cur%notfound;        
                  dbms_output.put_line(v_gsmno);
             end loop;
             close emp_cur;
             
             open get_gsmno_cur('138');
             loop
                  fetch get_gsmno_cur into v_gsmno;
                  exit when get_gsmno_cur%notfound;        
                  dbms_output.put_line(v_gsmno);
             end loop;
             close get_gsmno_cur;
          end;
          /

上面這段匿名塊用來實現選號的功能,我們顯式的定義了一個get_gsmno_cur,然後根據不同的號段輸出當前系統中該號短對應的可用手機號碼。當然了,實際應用中沒人這麼用的,我只是用來說應一個顯式cursor的用法。

隱式cursor

隱式cursor當然是相對於顯式而言的,就是沒有明確的cursor的declare。在Oracle的PL/SQL中,所有的DML操作都被Oracle內部解析為一個cursor名為SQL的隱式遊標,只是對我們透明罷了。

另外,我們前面提到的一些迴圈操作中的指標for 迴圈,都是隱式cursor.

隱式cursor示例一:

CREATE TABLE zrp (str VARCHAR2(10));
          insert into zrp values ('ABCDEFG');
          insert into zrp values ('ABCXEFG');
          insert into zrp values ('ABCYEFG');
          insert into zrp values ('ABCDEFG');
          insert into zrp values ('ABCZEFG');
          COMMIT;
          
          SQL> begin
            2    update zrp SET str = 'updateD' where str like '%D%';
            3    ifSQL%ROWCOUNT
= 0 then 4 insert into zrp values ('1111111'); 5 end if; 6 end; 7 / PL/SQL procedure successfully completed SQL> select * from zrp; STR ---------- updateD ABCXEFG ABCYEFG updateD ABCZEFG SQL> SQL> begin 2 update zrp SET str = 'updateD' where str like '%S%'; 3 ifSQL%ROWCOUNT
= 0 THEN 4 insert into zrp values ('0000000'); 5 end if; 6 end; 7 / PL/SQL procedure successfully completed SQL> select * from zrp; STR ---------- updateD ABCXEFG ABCYEFG updateD ABCZEFG0000000 6 rows selected SQL>

隱式cursor示例二:

begin
            for rec in (select gsmno,status from gsm_resource) loop
                dbms_output.put_line(rec.gsmno||'--'||rec.status);
            end loop;
          end;
          /  

REFcursor

Ref cursor屬於動態cursor(直到執行時才知道這條查詢).

從技術上講,在最基本的層次靜態cursor和ref cursor是相同的。一個典型的PL/SQL游標按定義是靜態的。Ref游標正好相反,可以動態地開啟,或者利用一組SQL靜態語句來開啟,選擇哪種方法由邏輯確定(一個IF/THEN/ELSE程式碼塊將開啟一個或其它的查詢)。例如,下面的程式碼塊顯示一個典型的靜態SQL游標,游標C。此外,還顯示瞭如何通過使用動態SQL或靜態SQL來用ref游標(在本例中為L_CURSOR)來開啟一個查詢:

Declare
        type rc is ref cursor;
        cursor c is select * from dual;
        
        l_cursor rc;
      begin
        if (to_char(sysdate,'dd') = 30) then
            -- ref cursor with dynamic sql
            open l_cursor for 'select * from emp';
        elsif (to_char(sysdate,'dd') = 29) then
            -- ref cursor with static sql
            open l_cursor for select * from dept;
        else
             -- with ref cursor with static sql
             open l_cursor for select * from dual;
        end if;
        -- the "normal" static cursor 
        open c;
      end;
      /  

在這段程式碼塊中,可以看到了最顯而易見的區別:無論執行多少次該程式碼塊,游標C總是select * from dual。相反,ref游標可以是任何結果集,因為"select * from emp"字串可以用實際上包含任何查詢的變數來代替。

在上面的程式碼中,聲明瞭一個弱型別的REF cursor,下面再看一個強型別(受限)的REF cursor,這種型別的REF cursor在實際的應用系統中用的也是比較多的。

create table gsm_resource
      (
        gsmno varchar2(11),
        status varchar2(1),
        price  number(8,2),
        store_id varchar2(32)
      );
      insert into gsm_resource values('13905310001','0',200.00,'SD.JN.01');  
      insert into gsm_resource values('13905312002','0',800.00,'SD.JN.02');
      insert into gsm_resource values('13905315005','1',500.00,'SD.JN.01');
      insert into gsm_resource values('13905316006','0',900.00,'SD.JN.03');
      commit;
      
      SQL> declare
        2     type gsm_rec is record(
        3          gsmno  varchar2(11),
        4          status varchar2(1),
        5          price  number(8,2));
        6  
        7     type app_ref_cur_type is ref cursor return gsm_rec;
        8     my_cur app_ref_cur_type;
        9     my_rec gsm_rec;
       10  
       11  begin
       12     open my_cur for select gsmno,status,price
       13          from gsm_resource
       14          where store_id='SD.JN.01';
       15     fetch my_cur into my_rec;
       16     while my_cur%found loop
       17           dbms_output.put_line(my_rec.gsmno||'#'||my_rec.status||'#'||my_rec.price);
       18           fetch my_cur into my_rec;
       19     end loop;
       20     close my_cur;
       21  end;
       22  /
      
      13905310001#0#200
      13905315005#1#500
      
      PL/SQL procedure successfully completed