一、遊標的分類
Oracle數據庫提供了倆種遊標類型,分別爲靜態遊標和動態遊標,而靜態遊標又分爲隱士遊標和顯式遊標,動態遊標分爲弱類型和強類型倆種。
二、靜態遊標
1、顯式遊標
1).聲明遊標語法:
cursor 遊標名 [(遊標輸入參數1[,遊標輸入參數2]…)]
[return 返回類型] is 查詢語句
遊標名:指定義的遊標名稱,一般採用cursor_名稱這種命名格式。
遊標輸入參數:爲遊標指定輸入參數,注意指定參數類型時,不能約束長度,比如NUMBER(10)是錯誤的。
返回類型:表示遊標提取的一行數據的類型
查詢語句:遊標所使用的查詢語句
遊標參數和返回類型用[]圈起來表示是可以省略的條件,聲明遊標時可以不加這倆個參數
2).打開遊標語法:
open 遊標名 [所有定義的遊標輸入參數]
3).提取遊標語法:
fetch 遊標名 into 接收變量
4).關閉遊標語法:
close 遊標名
使用示例:
--檢索EMP表中的所有JOB爲MANAGER的僱員信息
DECLARE
/*聲明遊標、(遊標輸入參數變量爲VAR_JOB)可選項*/
CURSOR CUR_EMP(VAR_JOB IN VARCHAR2:='SALESMAN') IS
/*遊標所使用的查詢語句*/
SELECT EMPNO, ENAME, SAL FROM EMP WHERE JOB = VAR_JOB;
/*聲明一個RECORD類型的記錄變量*/
TYPE RECORD_EMP IS RECORD(
VAR_EMPNO EMP.EMPNO%TYPE,
VAR_ENAME EMP.ENAME%TYPE,
VAR_SAL EMP.SAL%TYPE);
EMP_ROW RECORD_EMP;
BEGIN
/*打開遊標,指定輸入參數值爲MANAGER*/
OPEN CUR_EMP('MANAGER');
/*將遊標指向結果集第一行數據並存入RECORD記錄變量*/
FETCH CUR_EMP
INTO EMP_ROW;
/*如果遊標有數據就循環*/
WHILE CUR_EMP%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('僱員編號:' || EMP_ROW.VAR_EMPNO || ' 僱員姓名:' ||
EMP_ROW.VAR_ENAME || ' 僱員薪水:' || EMP_ROW.VAR_SAL);
/*將遊標指向結果集下一條數據*/
FETCH CUR_EMP
INTO EMP_ROW;
END LOOP;
/*關閉遊標*/
CLOSE CUR_EMP;
END;
--另一種方式,使用%ROWTYPE類型
DECLARE
CURSOR CUR_EMP IS
/*使用FETCH+%ROWTYPE查詢這裏的查詢字段必須和表中字段順序及數量一致*/
SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO FROM EMP;
/*定義一個%ROWTYPE接收變量*/
VAR_EMP_TYPE EMP%ROWTYPE;
BEGIN
OPEN CUR_EMP;
FETCH CUR_EMP
INTO VAR_EMP_TYPE;
WHILE CUR_EMP%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('僱員編號:' || VAR_EMP_TYPE.EMPNO || ' 僱員姓名:' ||
VAR_EMP_TYPE.ENAME || ' 僱員薪水:' ||
VAR_EMP_TYPE.SAL);
FETCH CUR_EMP
INTO VAR_EMP_TYPE;
END LOOP;
CLOSE CUR_EMP;
END;
顯示遊標具有以下屬性:
2、隱式遊標
PL/SQL爲所有SQL數據操縱語句(包括返回一行的SELECT)隱士聲明遊標,稱爲隱式遊標的原因是用戶不能直接命名和控制此類遊標。當用戶在PL/SQL中使用數據操縱語言(DML)時,Oracle預先定義一個名爲SQL的隱士遊標,通過檢查隱式遊標的屬性可以獲取與最近執行的SQL語句相關的信息。
隱式遊標屬性表如下:
使用示例:
--將EMP表中SALESMAN的工資加100,使用隱士遊標sql的%rowcount屬性輸出增加工資的員工數量
DECLARE
BEGIN
UPDATE EMP SET SAL = SAL + 100 WHERE JOB = 'SALESMAN';
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('沒有符合條件的僱員');
ELSE
DBMS_OUTPUT.PUT_LINE('上調了:' || SQL%ROWCOUNT || '個僱員的工資');
END IF;
END;
三、動態遊標
靜態遊標在使用時,使用的查詢語句已經確定,如果需要在運行的時候動態的絕對執行哪種查詢,可以使用REF遊標(動態遊標)和遊標變量。
1).聲明遊標的語法
聲明REF遊標需要2個步驟:聲明REF的遊標類型和聲明使用此類型的遊標變量。
聲明遊標類型的語法:
type 遊標類型名稱 is ref cursor
[return 遊標返回值類型]
遊標類型名稱:定義的一個遊標變量的類型,一般採用ref_type_類型名 這種格式。
遊標返回值類型:可選項,定義遊標變量的返回值類型,注意必須爲記錄變量。
REF遊標分爲強類型和弱類型倆種,在定義遊標變量類型時,如果指定了遊標變量的返回值類型,那麼就是強類型,如果沒指定,就是弱類型。並且一旦指定了返回值類型,在打開遊標時,綁定的查詢結果的返回集一定是return中定義的類型.
聲明遊標變量的語法:
遊標變量名稱 遊標類型名稱
2).打開遊標的語法:
open 遊標變量名 for 查詢語句
3).提取遊標,同顯式遊標。
4).關閉遊標同顯式遊標。
使用示例:
--弱類型
--將薪水低於3000的僱員薪水增加500,增加後最高不超過3000
DECLARE
TYPE REF_CURSOR_TYPE IS REF CURSOR; --聲明一個弱類型的動態遊標類型
REF_CURSOR REF_CURSOR_TYPE; --定義一個遊標爲聲明的弱類型遊標
V_SAL EMP.SAL%TYPE;--聲明一個變量用來接收僱員薪水
V_EMPNO EMP.EMPNO%TYPE;--聲明一個變量用來接收僱員編號
BEGIN
OPEN REF_CURSOR FOR
SELECT SAL, EMPNO FROM EMP;--打開遊標並指定使用的SQL語句
LOOP
FETCH REF_CURSOR
INTO V_SAL, V_EMPNO;--將遊標指向一行數據並給變量賦值
EXIT WHEN REF_CURSOR%NOTFOUND;--當遊標無數據時退出
IF V_SAL < 3000 THEN--薪水低於3000進入IF,這個IF最後會執行更新SQL
IF V_SAL >= 2500 THEN--薪水低於3000又大於2500進入這個IF
V_SAL := 3000;
ELSE
V_SAL := V_SAL + 500;
END IF;--結束一個IF,一個IF對應一個END IF;
UPDATE EMP SET SAL = V_SAL WHERE EMPNO = V_EMPNO;--更新僱員薪水
END IF;--結束最外層IF
END LOOP;--結束LOOP循環
CLOSE REF_CURSOR;--關閉遊標
END;
--強類型
--查詢所有僱員姓名
DECLARE
TYPE EMP_REF_CURSOR IS REF CURSOR RETURN EMP%ROWTYPE;--聲明一個強類型(指定返回類型)的動態遊標
REF_CURSOR EMP_REF_CURSOR;--定義一個聲明的強類型遊標
V_EMP_RECORD EMP%ROWTYPE;--定義一個接收變量
BEGIN
OPEN REF_CURSOR FOR
SELECT * FROM EMP;
LOOP
FETCH REF_CURSOR
INTO V_EMP_RECORD;
EXIT WHEN REF_CURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(V_EMP_RECORD.ENAME);
END LOOP;
CLOSE REF_CURSOR;
END;
四、通過for語句循環遊標
使用for語句循環遊標可以簡化顯式遊標的處理代碼。for語句循環遊標隱式的打開遊標,自動從活動集獲取行、然後在處理完所有行時關閉遊標。循環遊標自動創建%ROWTYPE類型的變量並將此變量用做記錄索引。
語法:
for 記錄變量 in 遊標變量
loop
//操作記錄變量
end loop;
記錄變量是PL/SQL聲明的記錄變量,此變量的屬性聲明爲%ROWTYPE類型,作用域在for循環之內,for循環之外不能訪問此變量。
for語句循環遊標特性:
1、在從遊標中提取了所有記錄之後自動終止。
2、提取和處理遊標中的每一條記錄。
3、如果在提取之後%NOTFOUND屬性返回TRUE,則終止循環。如果未返回行,則不進入循環。
使用示例:
--查詢所有僱員姓名
DECLARE
CURSOR EMP_CURSOR IS SELECT * FROM EMP;
BEGIN
/*使用for語句循環遊標無需手動打開/關閉遊標*/
FOR V_EMP_RECORD IN EMP_CURSOR LOOP
DBMS_OUTPUT.PUT_LINE(V_EMP_RECORD.ENAME);
END LOOP;
END;
五、NO_DATA_FOUND和%NOTFOUND的區別
1、SELECT…INTO語句返回0條和多條記錄時觸發NO_DATA_FOUND。
2、當UPDATE或DELETE語句的WHERE子句未找到時觸發%NOTFOUND。
3、在提取循環中要用%NOTFOUND或%FOUND來確定循環的退出條件,不要使用NO_DATA_FOUND。