Oracle 第6章 遊標



Oracle 第5章 使用PL/SQL

Oracle 第7章 子程序、程序包

Oracle 第6章 遊標


1、技術目標

  • 遊標的使用


2、什麼是遊標?

遊標是查詢數據時指向結果集的指針,通過遊標可一次訪問結果集中
的一行,Oracle有兩種遊標:

  • 靜態遊標 ,在編譯時知道select語句的遊標,靜態遊標有兩種:

    • 隱式遊標
    • 顯示遊標

  • REF遊標 ,有時候爲遊標使用的查詢直到代碼運行時才確定,
            這種情況使用REF遊標(引用遊標)和遊標變量來實現,
            有兩種REF遊標:


    • 強類型REF遊標
    • 弱類型REF遊標


3、隱式遊標

PL/SQL爲DML語句隱式聲明遊標,用戶不能命名和控制這種遊標,所以
稱爲隱式遊標,隱式遊標使用屬性返回信息,屬性 包括:

  • %FOUND ,在DML語句影響一行或多行時返回true
  • %NOTFOUND ,沒有影響任何行時返回true
  • %ROWCOUNT ,返回DML語句影響行數,如DML沒有影響任何行返回0
  • %ISOPEN ,返回遊標是否已打開的值,在SQL語句執行完後,Oracle自動關閉SQL遊標,隱式遊標的%ISOPEN屬性始終爲false


注意:通過檢查隱式遊標的屬性可以獲取與最近執行時的SQL語句相關的信息

使用1: 用%FOUND屬性判斷是否獲取查詢結果,

set serveroutput on
begin
    --查詢
    update toys set toyprice=270 where toyid='T005';
    --判斷是否有查詢結果
    if SQL%FOUND then
        DBMS_OUTPUT.PUT_LINE('表已更新');
    else
        DBMS_OUTPUT.PUT_LINE('編號未找到');
    end if;
end;
/

 


使用2: 用%ROWCOUNT獲取SQL語句執行所影響的行數,

set serveroutput on
begin
    update vendor_master set venname='Rob Mathew' where vencode='V004'
    DBMS_OUTPUT.PUT_LINE('更新了' || SQL%ROWCOUNT || '行');
end;
/

 


使用3 :按編號查詢員工,判斷是否查到,

set serveroutput on
declare
    empid varchar2(10);
    desig varchar2(20);
begin
    empid := '&職員編號';
    --根據員工編號查詢出員工職位並給變量desig賦值
    select designation into desig from employee where empno = empid;
    if SQL%ROWCOUNT > 0 then
        DBMS_OUTPUT.PUT_LINE('職員的頭銜是:' + desig);
    end if;
    exception
        when NO_DATA_FOUND then
            DBMS_OUTPUT.PUT_LINE('職員未找到');
end;
/

 


4、顯示遊標

顯示遊標是用戶顯示聲明的遊標,遊標將指向活動集(查詢結果)中的當前行,
使用顯示遊標的步驟:

    1)聲明
    2)打開
    3)從遊標中獲取記錄
    4)關閉遊標


顯示遊標在PL/SQL程序的DECLARE部分聲明,語法 爲:

CURSOR cursor_name [(parameter [, parameter] ...)]
[return return_type]
IS
select_statement;

語法說明:

cursor_name:遊標名稱
parameter:指定輸入參數
return type:定義遊標提取的行的類型
select_statement:遊標定義的查詢語句

遊標聲明後,可使用如下語句控制遊標

  • open :打開遊標,open cursor_name [ (parameters) ];
  • fetch :從遊標中提取行,fetch cursor_name into variables;
    寫在循環內,用於從結果集中一次檢索一行,
    每次提取後指針就向前移動一行
  • close :關閉遊標,close cursor_name,遊標處理完後必須關閉


使用1: 聲明遊標toy_cur,打開並使用該遊標提取所有行,

set serveroutput on
declare
    --定義變量my_toy_price,其類型與toyprice字段一致
    my_toy_price toys.toyprice%TYPE;
    CURSOR toy_cur IS
        select toyprice from toys
        where toyprice < 250;
begin
    open toy_cur; --打開遊標
    LOOP --循環
        --循環提取玩具的價格並給變量my_toy_price賦值
        fetch toy_cur into my_toy_price;
        --當查詢沒有返回任何行時退出循環
        exit when toy_cur%NOTFOUND;
        --輸出玩具價格
        DBMS_OUTPUT.PUT_LINE(toy_cur%ROWCOUNT || '. 玩具單價:' || my_toy_price);
    END LOOP;
    --關閉遊標
    close toy_cur;
end;
/

 

使用2: 用遊標操作PRODUCTDETAILS表,

declare
    --定義變量pro_price,其類型與PRODPRICE字段一致
    pro_price PRODUCTDETAILS.PRODPRICE%TYPE;
    --定義變量pro_name,其類型與PRODNAME字段一致
    pro_name PRODUCTDETAILS.PRODNAME%TYPE;
    --定義遊標pro_cur,查詢所有價格小於5000的商品
    CURSOR pro_cur IS
        select PRODNAME, PRODPRICE from PRODUCTDETAILS
        where PRODPRICE < 5000;
begin
    open pro_cur; --打開遊標
    LOOP --循環
        --循環提取商品的名稱和價格並賦值給變量pro_name和pro_price
        fetch pro_cur into pro_name, pro_price;
        --當查詢沒有返回任何行時退出循環
        exit when pro_cur%NOTFOUND;
        --輸出商品名、價格
        DBMS_OUTPUT.PUT_LINE(pro_cur%ROWCOUNT || ', 商品名:' || pro_name || ', 單價:' || pro_price);
    END LOOP;
    --關閉遊標
    close pro_cur;
end;
/

 


5、使用顯示遊標刪除或更新

語法:cursor cursor_name is select語句 for update [of colums];
注意:select語句只能包括一個表

遊標聲明中使用FOR UPDATE子句後,可使用以下語法更新行:

update 表名 set column_name = column_value
where CURRENT OF cursor_name;

注意:update命令中使用的列也必須出現在for update of子句中,
update和delete語句只有在打開遊標並提取到特定行後才能使用


使用: 用顯示遊標更新行,將所有價格低於100的玩具提價10%,

set serveroutput on
declare
    new_price number;
    --定義遊標
    cursor cur_toy is
    select toyprice from toys where toyprice < 100 for update of toyprice;
begin
    open cur_toy;--打開遊標
    LOOP
        --執行SQL查詢語句,提取價格並賦值給變量new_price
        fetch cur_toy into new_price;
        --如果沒有查詢結果,退出循環
        exit when cur_toy%NOTFOUND;
        --給價格低於100的商品提價10%
        update toys set toyprice = 1.1 * new_price where CURRENT OF cur_toy;
    end loop;
    close cur_toy;
    commit;
end;
/

 


6、帶參的顯示遊標

顯示遊標可以接受輸入的參數,聲明帶參遊標的語法 如下:

CURSOR cursor_name (<param_name> data_type)
[return <return_type>]

IS

select_statement;

使用: 提示輸入部門編號,根據輸入的部門編號提取該部門
下的員工,顯示員工的編號和姓名,

declare
    dept_code emp.deptno%TYPE;
    emp_code emp.empno%TYPE;
    emp_name emp.ename%TYPE;
    --定義帶參遊標,參數名爲deptparam,查詢指定部門的員工
    cursor emp_cur (deptparam number) is
        select empno, ename from emp
        where deptno=deptparam;--查詢條件使用參數匹配
begin
    --輸入部門編號
    dept_code := '&部門編號';
    open emp_cur(dept_code);--打開遊標的同時傳參
    LOOP --循環
        --取出員工編號、員工名並賦值給變量emp_code、emp_name
        fetch emp_cur into emp_code, emp_name;
        --沒有查詢出結果退出循環
        exit when emp_cur%NOTFOUND;
        --系統輸出
        DBMS_OUTPUT.PUT_LINE(emp_code || ' ' || emp_name);
    END LOOP;
    --關閉遊標
    close emp_cur;
end;
/

 


7、使用循環遊標簡化顯示遊標的代碼

當用戶需要從遊標中提取所有記錄時使用循環遊標,可自動從結果集
中獲取行,處理完所有行後關閉遊標,循環遊標還自動創建%ROWTYPE
類型的變量並將該變量作爲記錄索引,語法 如下:

FOR row_record IN cursor_name
LOOP
    語句;
END LOOP ;

語法說明:
row_record,保存行記錄的變量,爲%ROWTYPE類型,FOR循環外不能訪問
cursor_name,遊標名稱

循環遊標的特點:

  • 在從遊標中提取了所有記錄後自動終止
  • 可提取和處理遊標中的每一條記錄
  • 如果在提前記錄後%NOTFOUND屬性返回true,會終止循環,如果沒有
    返回任何行,不會進入循環


使用: 輸出顯示所有玩具的編號、名稱、價格,

SET SERVER OUTPUT ON
DECLARE
      CURSOR mytoyCur IS
        SELECT toyid, toyname, toyprice
        FROM toys;
BEGIN
      FOR toyRec IN mytoyCur
      LOOP
            DBMS_OUTPUT.PUT_LINE(
                         '玩具編號:' || ' ' || toyRec.toyid||' '           
            || ‘玩具名稱:' || ' '|| toyRec.toyname||' '
            || ‘玩具單價:' || ' '||toyRec.toyprice);
      END LOOP;
END;
/

 

處理帶參的循環遊標語法如下:

FOR row_record IN cursor_name (parameters)
LOOP
    語句;
END LOOP ;

8、REF 遊標和遊標變量

隱式/顯示遊標在使用它們的時候查詢語句已確定,如需在運行時動態
決定執行什麼查詢,可使用REF遊標和遊標變量

創建遊標變量需要兩個步驟:

  • 聲明REF遊標類型
  • 聲明REF遊標類型的變量


用於聲明REF遊標類型的語法 爲:

    TYPE ref_cursor_name
    IS REF CURSOR
    [RETURN return_type];

語法說明:

return可選子句用於指定遊標提取結果集的返回類型,如果
包含return子句表示強類型REF遊標,不包含return則爲弱
類型REF遊標

定義好遊標、遊標變量後,可在PL/SQL的執行部分打開REF遊標,語法爲:
OPEN cursor_name FOR select_statement;
注意:提取和關閉遊標的語法與顯示遊標相似

使用: 接收用戶輸入,選擇查看員工信息或者部門信息,

set serveroutput on
--accept命令可接收用戶輸入並存入變量tab中
ACCEPT tab PROMPT '你想查看什麼信息?員工信息(E),部門信息(D):';
DECLARE
    --聲明REF遊標(弱類型)
    TYPE refCurT IS REF CURSOR;
    --聲明遊標變量refCur
    refCur refCurT;
    pId number;
    pName varchar2(100);
    --定義變量selection保存用戶輸入的字符(E或D)
    selection varchar2(1) := UPPER(SUBSTR('&tab'), 1, 1);
BEGIN
    --判斷用戶輸入的是不是'E'
    IF selection = 'E' THEN
        --打開遊標,同時指定select語句
        OPEN refCur FOR
            --查詢員工表
            select empNo id, empName name
            from emp;
        --準備顯示員工信息
        DBMS_OUTPUT.PUT_LINE('===員工信息===');
    ELSIF selection = 'D' THEN
        --打開遊標,同時指定select語句
        OPEN refCur FOR
            --查詢部門表
            select depNo id, depName name
            from dept;
        --準備顯示部門信息
        DBMS_OUTPUT.PUT_LINE('===部門信息===');
    ELSE
        --提示輸入
        DBMS_OUTPUT.PUT_LINE('請輸入員工信息(E) 或 部門信息(D)');
        RETURN;
    END IF;
    --從遊標中提取編號、名稱,賦值給變量pId、pName
    FETCH refCur INTO pId, pName;
    --循環提取所有信息並顯示
    WHILE refCur%FOUND LOOP
        --顯示信息
        DBMS_OUTPUT.PUT_LINE('編號:' || pId || ' 名字:' || pName);
        --從遊標中提取編號、名稱,賦值給變量pId、pName
        FETCH refCur INTO pId, pName;
    END LOOP;
    --關閉遊標
    CLOSE refCur;
END;
/

 


9、使用REF遊標執行動態SQL語句

EXECUTE IMMEDIATE語句只能處理返回單行或沒有返回的SQL語句,
REF遊標可處理返回結果集的動態SQL,語法如下:

OPEN cursor_name
FOR
動態SQL語句字符串
[USING 綁定的輸入參數]

注意:這種遊標,聲明部分與普通REF遊標相同,只是OPEN語法不一樣

使用: 顯示薪水高於2500的員工信息,

SET SERVEROUTPUT ON
VARIABLE maxSal NUMBER
EXECUTE :maxSal := 2500
DECLARE
    empRec emp%ROWTYPE;
    --定義REF遊標
    TYPE cType IS REF CURSOR;
    --定義遊標變量
    cur cType;
    --薪水
    pSalary number;
BEGIN
    pSalary := :maxSal;
    --打開遊標,設置SQL字符串
    OPEN cur FOR
    'select * from Emp where sal > :inputSal order by sal desc';
    USING pSalary --使用變量pSalary的值作爲輸入參數傳遞給:inputSal
    --循環顯示出所有薪水大於指定值的員工
    LOOP
        --使用遊標提取行
        FETCH cur INTO empRec;
        --判斷所有行是否讀取完畢,讀取完畢需退出循環
        EXIT WHEN cur%NOTFOUND;
        --顯示信息
        DBMS_OUTPUT.PUT_LINE('編號:' || empRec.empNo
        || ' 姓名:' || empRec.eName || ' 薪水:' || empRec.sal);
    END LOOP;
    --關閉遊標
    CLOSE cur;
END;
/

 


10、遊標變量的優點和限制


遊標變量的優點 有:

  • 可從不同的SELECT語句中提取結果集
  • 可以作爲過程的參數進行傳遞
  • 可以引用遊標的所有屬性
  • 可以進行賦值運算


使用遊標變量的限制:

  • 不能在程序包中聲明遊標變量
  • FOR UPDATE子句不能與遊標變量一起使用
  • 不能使用比較運算符


11、總結

  • 遊標用於處理查詢結果集中的數據
  • 遊標類型有:隱式遊標、顯式遊標 和 REF 遊標
  • 隱式遊標由PL/SQL自動定義、打開和關閉
  • 顯式遊標用於處理返回多行的查詢
  • 顯式遊標可以刪除和更新活動集中的行
  • 要處理結果集中所有記錄時,可使用循環遊標
  • 在聲明REF遊標時,不需要將 SELECT 語句與其關聯


Oracle 第5章 使用PL/SQL

Oracle 第7章 子程序、程序包

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章