Oracle中的游標有兩種:
- 顯式游標
用CURSOR...IS 命令定義的游標,它可以對查詢語句(SELECT)返回的多條記錄進行處理。
- 隱式游標
是在執行插入(INSERT)、刪除(DELETE)、修改(UPDATE)和返回單條記錄的查詢(SELECT)語句時有PL/SQL自動定義的。
1、顯式游標操作
顯式游標在塊定義部分、包或子程序中聲明。當聲明了顯式游標后,可通過下面三條命令控制顯式游標操作。
1)打開游標
2)推進游標
3)關閉游標
--聲明顯式游標 聲明顯式游標就是指定游標名和與它關聯的SELECT語句,其語法如下: CURSOR cursor_name[(parameter[,parameter]...)][RETURN return_type] IS select_statement; parameter子句語法: cursor_parameter_name[IN]datatype[{:=|DEFAULT} expr] cursor_name是游標名,必須符合PL/SQL標識符的命名規范; return_type 是游標返回的查詢結果集類型,它只能是一個PL/SQL記錄類型或數據庫表的某一列的類型。 select_statement是游標中的SELECT語句,在游標中指定的SELECT語句可以帶有UNION、MINUS或INTERSECT子句。select_statement不能含有INTO子句,查詢結果是用FETCH語句中的INTO子句送給變量的。 將PL/SQL變量綁定在游標的WHERE子句中 DECLARE v_auths auths%ROWTYPE; v_code auths.author_code%TYPE; CURSOR c_auths IS SELECT * FROM auths WHERE author_code=v_code; 因為聲明游標時將PL/SQL變量綁定在WHERE子句中,所以游標的聲明必須在這些變量的作用域內,同時先聲明變量在聲明顯式游標。 將游標參數綁定在游標的WHERE子句中 DECLARE CURSOR c_auths(p_code auths.author_code%TYPE;) IS SELECT * FROM auths WHERE author_code=p_code; 游標參數的作用域只局限在游標聲明所指定的查詢中,並且游標可以賦缺省值。 --打開顯式游標 處理:先查找綁定在游標中的變量,然后按照該變量的值確定查詢結果集。 語法: OPEN cursor_name [(parameter[,parameter]...)] cursor_name是已聲明的游標的名; parameter是綁定的實參; BEGIN --在打開游標前為綁定的變量賦值 v_code:='A0001'; --打開游標 OPEN c_auths; 如果打開游標后,在為改變量賦值,查詢結果集不發生任何改變。這是因為結果集在游標打開時被確定,同時指向結果集的指針也被確定。 BEGIN --打開游標時將參數傳入 OPEN c_auths('A0001'); --推進顯式游標 使用FETCH語句來推進游標,返回查詢結果集中的一行,沒執行完一條FETCH語句后,顯式游標會自動指向查詢結果集的下一行。 語法: FETCH cursor_name INTO list_of_variables; 或 FETCH cursor_name INTO PL/SQL_record; cursor_name是已聲明的游標的名 list_of_variables是已聲明的變量列表 PL/SQL_record是已定義好的PL/SQL記錄 INTO子句中的變量必須與游標SELECT語句中相應表列的類型兼容(一致或可以自動轉換) --關閉顯式游標 當整個結果集都檢索完以后,應當關閉游標,釋放游標所占用的資源。 語法: CLOSE cursor_name 游標處於關閉狀態時,推進游標時錯誤的,錯誤信息如下: ORA-1001:Invalid CURSOR 或 ORA-1002:Fetch out of Sequence 如果關閉游標有又執行關閉游標命令,還會提示ORA-1001錯誤。
2、游標的屬性
%FOUND 一個返回布爾值得屬性,如果FETCH語句返回了一行,則該屬性返回true,否則返回false。 如果在打開游標之前或關閉游標之后使用該屬性,會提示ORA-1001錯誤。當打開游標后沒有使用FETCH語句推進,則返回NULL; %NOTFOUND 與%FOUND意思相反,如果FETCH語句返回了一行,則改屬性返回false,否則返回true。其它和%FOUND相同。 %ISOPEN 用來確定相關游標是否打開,如果游標已打開,則返回true,否則返回false; %ROWCOUNT 返回游標推進的行數。如果在打開游標之前或關閉游標之后使用該屬性,會提示ORA-1001錯誤。
3、顯式游標的推進循環
DECLARE --聲明一個變量,這個變量用來接收游標返回的結果集。 v_Salary Auths.salary%TYPE; v_Code Auths.author_code%type; --聲明游標,結果集為作家代碼A0001到A0006的工資值 CURSOR c_salary IS SELECT salary,author_code FROM auths WHERE author_code<='A0006' BEGIN --打開游標,並初始化結果集 OPEN c_salary; LOOP --推進游標,將游標的查詢結果集中的一行存到變量v_salary中。 FETCH c_salary INTO v_Salary,v_Code; --當結果集中沒有夯實退出循環。 EXIT WHEN c_salary%NOTFOUND; IF v_Salary<=200 THEN UPDATE auths SET salary=salary=50; WHERE author_code=v_Code; END IF; END LOOP; --關閉游標 CLOSE c_salary; --提交所做修改 COMMIT; END; PL/SQL還提供了一種簡單類型的循環,可以自動控制游標的打開、推進和關閉。 DECLARE CURSOR c_salary IS SELECT salary FROM auths WHERE author_code<='A0006' BEGIN --開始游標FOR循環,隱含地打開c_salary游標。 FOR v_salary IN c_salary LOOP --一個隱含的FETCH語句在這里被執行 IF v_Salary<=200 THEN UPDATE auths SET salary=salary=50; WHERE salary=v_salary.salary; END IF; --循環繼續前進,一個隱含的v_salary%NOTFOUND被檢測。 END LOOP; --循環結束,c_salary游標的一個隱含的CLOSE操作被執行。 COMMIT; END; v_salary沒有在塊的定義部分聲明,該變量被PL/SQL編譯器隱含地聲明了,該變量的類型為c_salary%ROWTYPE,其作用域只在循環內部。在循環開始,游標的c_salary被自動打開。在每一次自動推進后,%FOUND屬性用來檢查在結果集中是否還有行,當結果集中沒有行時,游標被自動關閉。 使用CURRENT OF cursor_name子句作為條件。 DECLARE --聲明游標時在SELECT語句中必須加FOR UPDATE OF 子句 CURSOR c_salary IS SELECT salary FROM auths WHERE author_code<='A0006' FOR UPDATE OF salary; BEGIN FOR v_salary IN c_salary LOOP IF v_Salary<=200 THEN UPDATE auths SET salary=salary=50; WHERE CURRENT OF c_salary; END IF; END LOOP; COMMIT; END;
4、隱式游標處理(SQL游標)
%FOUND 當使用INSERT、DELETE或UPDATE語句處理一行或多行,或換行SELECT INTO 語句返回一行時,返回true,否則返回false; 如果執行SELECT INTO語句時返回多行,則會產生TOO_MANY_ROWS異常,並將控制權轉到異常處理部分,%FOUND屬性並不返回true,如果執行SELECT INTO語句時返回0行,會產生NO_DATA_FOUND異常,%FOUND屬性並不返回false。 %NOTFOUND 與%FOUND屬性相反,當使用INSERT、DELETE或者UPDATE語句處理的行數為0時,%NOTFOUND屬性返回true,否則返回false。 %ISOPEN 因為在執行了DML語句后,Oracle會自動關閉SQL游標,所以該屬性終為false。 %ROWCOUNT 該屬性返回執行INSERT、DELETE或者UPDATE語句返回的行數,或返回執行SELECT INTO 語句時查詢出的行數,如果INSERT、DELETE、UPDATE或者SELECT INTO語句返回的行數為0,則%ROWCOUNT屬性返回0。但如果SELECT INTO語句返回的行數為多行,則產生TOO_MANY_ROWS異常,並將控制權轉到異常處理部分,而不是去判斷%ROWCOUNT屬性。 BEGIN UPDATE auths SET entry_date_time=SYSDATE WHERE author_code='A0001'; IF SQL%NOTFOUND THEN INSERT INTO auths(author_code,name,entry_date_time) VALUES('A0001','張三',SYSDATE); END IF; END; SET SERVEROUTPUT ON DECLARE v_birthdate DATE; BEGIN SELECT birthdate INTO v_birthdate FROM auths WHERE name='張三'; IF SQL%FOUND THEN DELETE FROM auths WHERE name='張三'; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('該記錄不存在'); WHEN TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE('存在多條記錄'); END;
5、游標變量
這部分內容以后補上。