PL/SQL之游標的使用


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、游標變量

  這部分內容以后補上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM