簡介
PL/SQL 是用遊標來管理 SQL 的 SELECT 語句的 。遊標是爲了處理這些語句而分配的一大塊內存。 它提供了對一個結果集進行逐行處理的能力 , 可看作是一種特殊的指針 . 它與某個查詢結果集相關聯 , 可以指向結果集的任意位置 , 以便對指定位置的數據進行處理 。使用它可以在查詢數據的同時對數據進行處理。
遊標類型
隱式遊標
1、使用DML語句(增刪改)和單行查詢語句(賦值)時自動創建隱式遊標
2、隱式遊標自動聲明、打開和關閉,其名爲 SQL
3、通過檢查隱式遊標的屬性可以獲得最近執行的DML 語句的信息
4、隱式遊標的屬性:
(1)、%FOUND:SQL 語句影響了一行或多行時爲 TRUE。只有在 DML 語句影響一行或多行時,才返回 True。
BEGIN
UPDATE t_student SET sname = '張三丰'
WHERE sid= ‘10001';
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('表已更新');
END IF;
END;
(2)、%NOTFOUND : SQL 語句沒有影響任何行時爲TRUE。如果 DML 語句不影響任何行,則返回 True。
BEGIN
UPDATE emp SET deptno=20 WHERE empno=7839;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('編號未找到。');
ELSE
DBMS_OUTPUT.PUT_LINE(‘數據已更新');
END IF;
END;
(3)、%ROWCOUNT : SQL 語句影響的行數,沒有影響任何行,返回0,在執行任何DML語句前,值爲NULL。
如果沒有與SELECT INTO語句中的條件匹配的行,將引發NO_DATA_FOUND異常。
DECLARE
v_no emp.empno%type;
v_name emp.ename%type;
BEGIN
v_no:= &職員編號;
SELECT ename INTO v_name
FROM emp WHERE empno=v_no;
IF SQL%ROWCOUNT>0 THEN
DBMS_OUTPUT.PUT_LINE('職員的姓名是 '||v_name);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('職員未找到');
END;
(4)、%ISOPEN : 遊標是否打開,隱式遊標始終爲FALSE(隱式遊標執行時打開,結束時立即關閉)
顯示遊標
1、顯式遊標是由PL/SQL程序員定義和命名的遊標
2、顯式遊標用於多行查詢
3、顯式遊標需要在PL/SQL塊的聲明部分聲明,在執行部分或異常處理部分打開,取完數據後將其關閉
聲明遊標
CURSOR cursor_name IS select_statement;
打開遊標(將數據存儲到遊標)
OPEN cursor_name;
根據遊標提取數據
FETCH cursor_name INTO variable[,variable,……]
關閉遊標
CLOSE cursor_name;
使用遊標循環打印所有學生姓名
Declare
v_name t_student.sname%type;
Cursor cur_stu Is select sname from t_student; --聲明遊標
begin
Open cur_stu; --打開遊標
Loop
Fetch cur_stu Into v_name; --提取遊標指向數據給變量
Exit When cur_stu%NotFound;
dbms_output.put_line('學生姓名:'||v_name);
End Loop;
Close cur_stu; --關閉遊標
end;
使用遊標循環打印所有員工編號,員工姓名及工資
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
begin
Open c_emp;
Loop
Fetch c_emp Into v_empno,v_ename,v_sal;
Exit When c_emp%NotFound;
dbms_output.put_line(v_empno||’ ’||v_ename||’ ’||v_sal);
End Loop;
Close c_emp;
end;
使用遊標循環打印所有員工編號,員工姓名及工資
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
begin
Open c_emp;
Loop
Fetch c_emp Into v_empno,v_ename,v_sal;
Exit When c_emp%NotFound;
dbms_output.put_line(v_empno||’ ’||v_ename||’ ’||v_sal);
End Loop;
Close c_emp;
end;
使用遊標行循環打印員工編號,姓名,工資
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
r_emp c_emp%ROWTYPE;--遊標行
begin
Open c_emp;
Loop
Fetch c_emp Into r_emp;
Exit When c_emp%NotFound;
dbms_output.put_line(r_emp.empno||’ ’||r_emp.ename||’ ’||r_emp.sal);
End Loop;
Close c_emp;
end;
使用遊標行循環打印員工編號,姓名,工資
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
r_emp c_emp%ROWTYPE;--遊標行
begin
Open c_emp;
Loop
Fetch c_emp Into r_emp;
Exit When c_emp%NotFound;
dbms_output.put_line(r_emp.empno||’ ’||r_emp.ename||’ ’||r_emp.sal);
End Loop;
Close c_emp;
end;
帶參數的顯示遊標
聲明顯式遊標時可以帶參數以提高靈活性
declare
v_deptno emp.deptno%type; --部門編號變量
cursor c_emp(dno number) is
select empno,ename,sal from emp where deptno=dno;
r_emp c_emp%rowtype; --遊標行
begin
v_deptno:='&部門編號'; --輸入參數值
Open c_emp(v_deptno);--傳遞參數
Loop
Fetch c_emp Into r_emp;
Exit When c_emp%NotFound;
dbms_output.put_line(r_emp.empno||' '||r_emp.ename||' '||r_emp.sal);
End Loop;
Close c_emp;
end;
循環遊標
1、循環遊標用於簡化遊標處理代碼
2、當用戶需要從遊標中提取多行記錄時使用
3、循環遊標的語法如下:
FOR record_name IN (corsor_name[(parameter[,parameter])...])
| (query_difinition)
LOOP
statements
END LOOP;
DECLARE
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
BEGIN
FOR r_emp IN c_emp
Loop -- r_emp代表遊標行
dbms_output.put_line(r_emp.empno||’’||r_emp.ename||’’||r_emp.sal);
End Loop;
END;
用於FOR循環的遊標聲明按照正常聲明方式聲明;不需要顯式的打開,取數據,測試數據存在,關閉等;帶參數時,in 遊標名(參數)。
允許使用遊標刪除或更新活動集中的行,聲明遊標時必須使用 SELECT … FOR UPDATE語句
CURSOR <cursor_name> IS
select_statement FOR UPDATE [OF columns];
更新數據格式
UPDATE <table_name>
SET column_name = column_value
WHERE CURRENT OF <cursor_name>
刪除數據格式
DELETE FROM <table_name>
WHERE CURRENT OF <cursor_name>
DECLARE
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal DESC FOR UPDATE;
v_increase NUMBER:=0; --增加的工資數
v_new_sal NUMBER; --新工資
BEGIN
FOR r_emp IN c_emp LOOP
v_new_sal:=r_emp.sal+v_increase;
UPDATE emp SET sal=v_new_sal WHERE CURRENT OF c_emp;
DBMS_OUTPUT.PUT_LINE(r_emp.empno||' '||r_emp.ename||
' old salary ='||r_emp.sal||' new salary='||v_new_sal);
v_increase:=v_increase+100;
END LOOP;
END;
REF 遊標
REF 遊標和遊標變量用於處理運行時動態執行的 SQL 查詢,創建遊標變量需要兩個步驟:
1、聲明 REF 遊標類型
TYPE <ref_cursor_name> IS REF CURSOR
[RETURN <return_type>];
2、聲明 REF 遊標類型的變量
ref_variable ref_cursor_name;
打開遊標變量的語法
OPEN ref_variable FOR select_statement;
declare
type refcur is ref cursor;
ref_cur refcur;
r_emp emp%rowtype;
r_dept dept%rowtype;
selection varchar2(1):=upper(substr('&input',1,1));
begin
if selection='E' then
open ref_cur for select * from emp;
dbms_output.put_line('=========員工信息=========');
loop
fetch ref_cur into r_emp;
exit when ref_cur%notfound;
dbms_output.put_line(r_emp.empno||' '||r_emp.ename||' '||r_emp.sal);
end loop;
elsif selection='D' then
open ref_cur for select * from dept;
dbms_output.put_line('=========部門信息=========');
loop
fetch ref_cur into r_dept ;
exit when ref_cur%notfound;
dbms_output.put_line(r_dept.deptno||' '||r_dept.dname||' ');
end loop;
else
dbms_output.put_line('請輸入員工信息(E)或 部門信息(D)');
return;
end if;
close ref_cur;
end;
遊標變量的優點和限制
1、遊標變量的功能強大,可以簡化數據處理。
2、遊標變量的優點有:
(1)、可從不同的 SELECT 語句中提取結果集
(2)、可以作爲過程的參數進行傳遞
(3)、可以引用遊標的所有屬性
(4)、可以進行賦值運算
3、使用遊標變量的限制:
(1)、不能在程序包中聲明遊標變量
(2)、FOR UPDATE子句不能與遊標變量一起使用
(3)、不能使用比較運算符