*****************************
數據庫之遊標使用詳解篇
*****************************
遊標(Cursor):用來查詢數據庫,獲取記錄集合(結果集)的指針,可以讓開發者一次訪問一行結果集,
在每條結果集上作操作。遊標類型:隱式遊標,顯示遊標,REF遊標。
其中,隱式遊標和顯示遊標屬於靜態遊標(運行前將遊標與SQL語句關聯),
REF遊標屬於動態遊標(運行時將遊標與SQL語句關聯)。
隱式遊標:DML語句對應的遊標,由Oracle自動管理,也稱SQL遊標。
遊標變量的功能強大,可以簡化數據處理
遊標變量的優點有:
1.可從不同的 SELECT 語句中提取結果集
2.可以作爲過程的參數進行傳遞
3.可以引用遊標的所有屬性
4.可以進行賦值運算
使用遊標變量的限制:
1.不能在程序包中聲明遊標變量
2.FOR UPDATE子句不能與遊標變量一起使用
3.不能使用比較運算符
顯式和隱式遊標的區別:
儘量使用隱式遊標,避免編寫附加的遊標控制代碼(聲明,打開,獲取,關閉),
也不需要聲明變量來保存從遊標中獲取的數據。
--1.靜態遊標(隱式遊標和顯示遊標)
--1.1隱式遊標
--隱式遊標的屬性
%FOUND --有記錄爲真
%NOTFOUND --沒記錄時爲真
%ROWCOUNT --引響到表裏記錄的行數
%ISOPEN --遊標的狀態(OPEN,CLOSE)
SQL --所有隱式遊標的名稱
--隱式遊標屬性%FOUND的用法
BEGIN
UPDATE emp SET sal = 2000 WHERE empno = '7369';
IF SQL%FOUND THEN
--SQL%NOTFOUND
DBMS_OUTPUT.PUT_LINE('表已更新');
END IF;
END;
/
--未找到數據異常NO_DATA_FOUND
DECLARE
empid VARCHAR2(10);
desig VARCHAR2(10);
BEGIN
empid := '&Employeeid';
SELECT ename INTO desig FROM emp WHERE empno = empid;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('職員未找到');
END;
--隱式遊標屬性SQL%ROWCOUNT用法
BEGIN
UPDATE vendor_master SET venname = 'Rob Mathew' WHERE vencode = 'V004';
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
END;
/
--select into 時錯誤TOO_MANY_ROWS
DECLARE
empid VARCHAR2(10);
BEGIN
SELECT empno INTO empid FROM emp;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('該查詢提取多行');
END;
/
--1.2.顯示遊標
顯示遊標操作:
(1)聲明遊標(關聯SQL語句) cursor+遊標名 is/as sql語句
(2)打開遊標(執行SQL語句,填充遊標) open+遊標名
(3)提取遊標的行 fetch 遊標名 into 行類型變量
(4)關閉遊標 close+遊標名
declare
--定義存儲遊標變量
rowresult emp%rowtype;
--定義遊標
cursor cur is
select * from emp where sal > 2000;
begin
open cur; --打開
loop --循環
fetch cur
into rowresult; --提取
exit when cur%notfound; --退出
dbms_output.put_line('員工姓名:' || rowresult.ename); --從遊標變量中取某個字段值
end loop;
close cur; --關閉
end;
--帶參數的顯示遊標
declare
rowresult emp%rowtype;
cursor cur(eno number) is
select * from emp where empno = eno;
begin
open cur(&empno);
loop
fetch cur
into rowresult;
exit when cur%notfound;
dbms_output.put_line('用戶名是:' || rowresult.ename);
end loop;
close cur;
end;
--使用顯示遊標更新記錄
declare
new_sal number;
cursor cur is
select sal from emp where sal < 3000 for update of sal;
begin
open cur;
loop
fetch cur
into new_sal;
exit when cur%notfound;
update emp set sal = 1.1 * new_sal where current of cur;
dbms_output.put_line('記錄已經更新' || 1.1 * new_sal);
end loop;
close cur;
end;
--循環遊標
declare
cursor cur is
select ename, sal from emp;
begin
for new_cur in cur loop
dbms_output.put_line('員工:' || new_cur.ename || '的工資是:' || new_cur.sal);
end loop;
end;
--2.動態遊標(Ref遊標)
--2.1REF遊標
accept tab prompt '你想查看什麼信息? 員工信息(E)或部門信息(D):';--使用對話框輸入參數
declare
--定義引用遊標類型
type cur is ref cursor; --聲明遊標類型
/*如果不指定返回類型爲弱類型遊標,如果指定了返回類型則爲強類型,如下所示:*/
--return emp%rowtype;
--根據定義的引用遊標類型聲明遊標變量
new_cur cur;
p_id number;
p_name varchar2(200);
selection varchar2(1) := upper(substr('&tab', 1, 1)); --接收對話框輸入參數
begin
if selection = 'E' then
open new_cur for
select empno id, ename name from emp;
dbms_output.put_line('=====員工信息表=====');
elsif selection = 'D' then
open new_cur for
select deptno id, dname name from dept;
dbms_output.put_line('=====部門信息表=====');
else
dbms_output.put_line('請輸入員工信息(E)或部門信息(D)');
return;
end if;
/*fetch new_cur into p_id,p_name;
while new_cur%found loop
dbms_output.put_line('#'||p_id||':'||p_name);
fetch new_cur into p_id,p_name;
end loop;*/ --遞歸提取遊標數據方法
loop
--循環提取遊標數據方法
fetch new_cur
into p_id, p_name;
exit when new_cur%notfound;
dbms_output.put_line('#' || p_id || ':' || p_name);
end loop;
close new_cur;
end;
--使用公用變量的動態查詢語句
set serveroutput on;
variable aa number; --定義公用變量
execute :empno :=7369;--公用變量賦值
declare
sqlstr varchar2(2000);
emp_row emp%rowtype;
emno number;
begin
emno := :empno; --使用公用變量
sqlstr := 'select * from emp where empno=:id';
--執行動態SQL
execute immediate sqlstr
into emp_row
using emno;
dbms_output.put_line('編號爲:' || emno || '的工資爲:' || emp_row.sal);
end;
--使用遊標變量執行動態SQL
variable maxsal number;--在ORACLE中定義公用變量
execute :maxsal := 2500;--對公用變量賦值
declare
r_emp emp%rowtype;
type c_type is ref cursor;
cur c_type;
p_salary number;
begin
p_salary := :maxsal;
open cur for 'select * from emp where sal >:1 order by sal desc'
using p_salary; --引用公用變量,對WHERE條件的:1參數賦值
dbms_output.put_line('薪水大於' || p_salary || '的員工有:');
loop
fetch cur
into r_emp;
exit when cur%notfound;
dbms_output.put_line(':編號:' || r_emp.empno || '姓名' || r_emp.ename ||
'薪水:' || r_emp.sal);
end loop;
close cur;
end;