REF 遊標:
REF遊標又稱爲動態遊標,在運行時使不同的語句與之關聯,動態關聯結果集的臨時對象,即在運行的時候動態決定執行查詢。REF遊標可以使用遊標變量。
遊標變量:
遊標變量是一種引用REF遊標類型的變量,只想動態關聯的結果集。
遊標變量的類型:
1.具有約束的遊標變量,具有返回類型的遊標變量也稱爲強遊標。
2.無約束的遊標變量,沒有返回類型的遊標變量也稱爲弱遊標。
REF遊標的作用:
實現程序間傳遞結果集的功能,利用REF cursor 也可以實現bulk sql 從而提高sql性能。
靜態遊標和REF遊標的區別:
1.靜態遊標是靜態定義,REF遊標是動態關聯
2.使用REF遊標需要REF遊標變量
3.REF遊標可以作爲參數進行傳遞,而靜態遊標是不能作爲參數傳遞的。
REF遊標的語法:
1.強類型REF遊標:指定return datatype,REF遊標變量的類型必須和return datatype一致。
語法:TYPE TYPE_NAME IS REF CURSOR RETURN DATATYPE;
2.弱類型REF遊標:不指定return datatype 能和任何類型的cursor 變量匹配,用於獲取任何結果集。
語法:TYPE TYPE_NAME IS REF CURSOR;
SYS_REFCURSOR:
主要用在過程中返回結果集,如果僅僅爲了返回值,無需自己在包頭中定義遊標類型,只需直接使用sys_refcursor 即可輕鬆返回結果。
提示:
使用靜態光標--通過靜態SQL(但不用ref光標)--比使用ref光標效率高,而ref光標的使用僅限於以下幾種情況:
把結果集返回給客戶端;
在多個子例程之間共享光標(實際上與上面提到的一點非常類似);
沒有其他有效的方法來達到你的目標時,則使用ref光標,正如必須用動態SQL時那樣;
簡言之,首先考慮使用靜態SQL,只有絕對必須使用ref光標時才使用ref光標,也有人建議儘量使用隱式遊標,避免編寫附加的遊標控制代碼(聲明,打開,獲取,關閉),也不需要聲明變量來保存從遊標中獲取的數據。
PACKAGE
示例中涉及到包(package)和包體(package body)以下爲package 用法的說明:
包結構:
一個包由兩個分開的部分組成:包規範和包體
1.包定義(package):包定義部分是爲應用程序的接口,聲明包內數據類型、變量、常量、遊標、子程序和異常錯誤處理等元素,這些元素爲包的公有元素。
語法:
CREATE [OR REPLACE] PACKAGE PACKAGE_NAME
{IS|AS}
[公有數據類型定義]
[公有遊標聲明]
[公有變量、常量聲明]
[公有子程序聲明]
END [PACKAGE_NAME];
2.包主體(package body):包主體則是包定義部分的具體實現,它定義了包定義部分所聲明的遊標和子程序,在包主體中還可以聲明包的私有元素。如果在包主體中的遊標或子程序並沒有在包頭中定義,那麼這個遊標或子程序是私有的。
語法:
CREATE [OR REPLACE] PACKAGE BODY PACKAGE_NAME
{IS |AS}
[私有數據類型定義]
[私有變量、常量]
[私有子程序聲明和定義]
[公有子程序定義]
BEGIN
執行部分(初始化部分);
END [PACKAGE_NAME];
與類相同,包中的程序元素也分爲公有元素和私有元素兩種,這兩種元素的區別是他們允許訪問程序範圍不同,即他們的作用域不同。公有元素不僅可以被包中的函數、過程所調用也可以被包外的PL/SQL程序訪問,而私有元素只能被包內的函數和過程所訪問。包定義和包主體分開編譯,並作爲兩部分分開的對象存放在數據庫字典中。包定義一定要在包主體前面編譯,包主體可以沒有,但是包定義一定要有,包的名稱和包體的名稱要保持一致。
示例1:強類型REF遊標
DECLARE
TYPE REF_CURSOR IS REF CURSOR RETURN DJ_DJB%ROWTYPE;
------遊標僅能打開DJ_DJB表的數據
REF_C REF_CURSOR;
----遊標變量
V_DJB DJ_DJB%ROWTYPE;
SELECTION VARCHAR2(1):=('&請輸入:');
BEGIN
IF SELECTION='1' THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2016%' AND ROWNUM<10;
ELSIF SELECTION='2' THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2017%' AND ROWNUM<10;
END IF;
LOOP
FETCH REF_C INTO V_DJB;
EXIT WHEN REF_C%NOTFOUND;
DBMS_OUTPUT.ENABLE(BUFFER_SIZE=>NULL);
DBMS_OUTPUT.PUT_LINE(V_DJB.SLBH||','||V_DJB.BDCZH);
END LOOP;
CLOSE REF_C;
END;
示例2:弱類型REF遊標
DECLARE
TYPE REF_CURSOR IS REF CURSOR;
REF_C REF_CURSOR;
V_V1 VARCHAR2(100);
SELECTION VARCHAR2(1):=('&請輸入:');
BEGIN
IF SELECTION='1' THEN
OPEN REF_C FOR SELECT TO_CHAR(BDCZH) FROM DJ_DJB WHERE SLBH LIKE '2016%' AND ROWNUM<10;
-------弱類型遊標對目標表沒有限制,數據可以使來自任何表
ELSIF SELECTION='2' THEN
OPEN REF_C FOR SELECT TO_CHAR(QLRMC) FROM DJ_QLRGL WHERE SLBH LIKE '2017%' AND ROWNUM<10 AND QLRLX='權利人';
-------弱類型遊標對目標表沒有限制,數據可以使來自任何表
END IF;
LOOP
FETCH REF_C INTO V_V1;
EXIT WHEN REF_C%NOTFOUND;
DBMS_OUTPUT.ENABLE(BUFFER_SIZE=>NULL);
DBMS_OUTPUT.PUT_LINE('輸出結果值:'||V_V1);
END LOOP;
CLOSE REF_C;
END;
示例3:SYS_REFCURSOR
DECLARE
V_DJB DJ_DJB%ROWTYPE;
REF_C SYS_REFCURSOR; ---利用SYS_REFCUSOR 來聲明遊標變量
SELECTION VARCHAR2(1):=('&請輸入:');
BEGIN
IF SELECTION='1' THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2016%' AND ROWNUM<10;
ELSIF SELECTION='2' THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2017%' AND ROWNUM<11;
END IF;
LOOP
FETCH REF_C INTO V_DJB;
EXIT WHEN REF_C%NOTFOUND;
DBMS_OUTPUT.ENABLE(BUFFER_SIZE=>NULL);
DBMS_OUTPUT.PUT_LINE(V_DJB.SLBH||','||V_DJB.BDCZH);
END LOOP;
CLOSE REF_C;
END;
示例4:REF 遊標作爲參數傳遞
CREATE OR REPLACE PACKAGE EMP_T
IS
TYPE REF_CURSOR IS REF CURSOR RETURN DJ_DJB%ROWTYPE;
PROCEDURE GET_BDCZH(REF_C IN OUT REF_CURSOR,SELECTION VARCHAR2);
PROCEDURE RETURN_C(SELECTION VARCHAR2);
END;
CREATE OR REPLACE PACKAGE BODY EMP_T
IS
PROCEDURE GET_BDCZH (REF_C IN OUT REF_CURSOR,SELECTION VARCHAR2)
IS
BEGIN
IF SELECTION =1 THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2016%' AND ROWNUM<10;
ELSIF SELECTION=2 THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2017%' AND ROWNUM<10;
END IF;
END;
PROCEDURE RETURN_C (SELECTION VARCHAR2)
IS
V_1 REF_CURSOR;
V_DJB dj_djb%ROWTYPE;
BEGIN
GET_BDCZH(V_1,SELECTION);
LOOP
FETCH V_1 INTO V_DJB;
EXIT WHEN V_1%NOTFOUND;
DBMS_OUTPUT.ENABLE(BUFFER_SIZE=>NULL);
DBMS_OUTPUT.PUT_LINE(V_DJB.SLBH||','||V_DJB.BDCZH);
END LOOP;
CLOSE V_1;
END;
END;
---調用
begin
EMP_T.RETURN_C(1);
END;
示例5:使用BULK COLLECT INTO.......批量提取數據
DECLARE
TYPE REF_CURSOR IS REF CURSOR;
REF_C REF_CURSOR;
TYPE R_DJB IS TABLE OF DJ_DJB%ROWTYPE INDEX BY BINARY_INTEGER;
V_DJB R_DJB;
SELECTION VARCHAR2(1):=('&請輸入:');
BEGIN
IF SELECTION='1' THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2016%' AND ROWNUM<100;
ELSIF SELECTION='2' THEN
OPEN REF_C FOR SELECT * FROM DJ_DJB WHERE SLBH LIKE '2017%' AND ROWNUM<100;
END IF;
LOOP
FETCH REF_C BULK COLLECT INTO V_DJB LIMIT 10;
---EXIT WHEN REF_C%NOTFOUND;
DBMS_OUTPUT.ENABLE(BUFFER_SIZE=>NULL);
---FOR I IN 1..V_DJB.COUNT LOOP
FOR I IN V_DJB.FIRST..V_DJB.LAST LOOP
DBMS_OUTPUT.PUT_LINE(V_DJB(I).SLBH||','||V_DJB(I).BDCZH||'I 的值爲:'||I);
END LOOP;
DBMS_OUTPUT.PUT_LINE('ROWCOUNT的值:'||REF_C%ROWCOUNT);
EXIT WHEN REF_C%NOTFOUND;
END LOOP;
END;
BY WOLIAHAITO 2018.04.03