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 語句與其關聯