1. 程式人生 > >PLSQL中顯示Cursor、隱示Cursor、動態Ref Cursor差別

PLSQL中顯示Cursor、隱示Cursor、動態Ref Cursor差別

不同 number acl res 效率 track 一點 變量 語法

一、顯式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
??????? ABCZEFG
??????? 0000000
?????? 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
???
??? SQL>

普通cursor與REF cursor另一些大家應該都熟悉的差別。我再浪費點唾沫。

1)PL/SQL靜態光標不能返回到client。僅僅有PL/SQL才幹利用它。

ref光標能夠被返回到client,這就是從Oracle的存儲過程返回結果集的方式。

2)PL/SQL靜態光標能夠是全局的,而ref光標則不是。 也就是說,不能在包說明或包體中的過程或函數之外定義ref光標。 僅僅能在定義ref光標的過程中處理它,或返回到client應用程序。

3)ref光標能夠從子例程傳遞到子例程,而光標則不能。 為了共享靜態光標。必須在包說明或包體中把它定義為全局光標。 由於使用全局變量通常不是一種非常好的編碼習慣。因此能夠用ref光標來共享PL/SQL中的光標。無需混合使用全局變量。

最後。使用靜態光標--通過靜態SQL(但不用ref光標)--比使用ref光標效率高。而ref光標的使用僅限於以下幾種情況:

把結果集返回給client;
在多個子例程之間共享光標(實際上與上面提到的一點非常相似);
沒有其他有效的方法來達到你的目標時,則使用ref光標。正如必須用動態SQL時那樣。

簡言之,首先考慮使用靜態SQL,僅僅有絕對必須使用ref光標時才使用ref光標,也有人建議盡量使用隱式遊標,避免編寫附加的遊標控制代碼(聲明。打開,獲取,關閉)。也不須要聲明變量來保存從遊標中獲取的數據。這個就因人因具體的case大家去酌定吧。



四、遊標屬性

%FOUND: bool - TRUE if >1 row returned
%NOTFOUND:bool - TRUE if 0 rows returned
%ISOPEN: bool - TRUE if cursor still open
%ROWCOUNT:int - number of rows affected by last SQL statement

註:NO_DATA_FOUND和%NOTFOUND的使用方法是有差別的,小結例如以下:
1)SELECT . . . INTO 語句觸發 NO_DATA_FOUND。
2)當一個顯式光標的 where 子句未找到時觸發 %NOTFOUND;
3)當UPDATE或DELETE 語句的where 子句未找到時觸發 SQL%NOTFOUND。
4)在光標的提取(Fetch)循環中要用 %NOTFOUND 或%FOUND 來確定循環的退出條件,不要用NO_DATA_FOUND。



PLSQL中顯示Cursor、隱示Cursor、動態Ref Cursor差別