plsql--遊標用法
1.遊標概念
在 PL/SQL 塊中執行 SELECT、INSERT、DELETE 和 UPDATE 語句時,ORACLE 會在記憶體中為其分配上下文區(Context Area),即緩衝區。遊標是指向該區的一個指標,或
是命名一個工作區(Work Area),或是一種結構化資料型別。它為應用等量齊觀提供了一種對具有多行資料查詢結果集中的每一行資料分別進行單獨處理的方法,是設計嵌入式
SQL 語句的應用程式的常用程式設計方式。
在每個使用者會話中,可以同時開啟多個遊標,其數量由資料庫初始化引數檔案中的
OPEN_CURSORS 引數定義。
對於不同的 SQL 語句,遊標的使用情況不同:
非查詢語句--》 隱式的
結果是單行的查詢語句 --》隱式的或顯示的
結果是多行的查詢語句--》 顯示的
2.處理顯示遊標
2.1顯示遊標處理的4個步驟
1.定義/ / 宣告 遊標:就是定義一個遊標名,以及與其相對應的 SELECT 語句。
格式:
CURSOR cursor_name[(parameter[, parameter]…)]
[RETURN datatype]
IS
select_statement;
注意:1.遊標引數只能為輸入引數
2.在指定資料型別時,不能使用長度約束
3.[RETURN datatype]是可選的,表示遊標返回資料的資料。如果選擇,則應該嚴格與 select_statement 中的選擇列表在次序和資料型別上匹配。一般是記錄資料型別或帶“%ROWTYPE”的資料。
2.開啟遊標
就是執行遊標所對應的 SELECT 語句,將其查詢結果放入工作區,並且指
針指向工作區的首部,標識遊標結果集合。如果遊標查詢語句中帶有 FOR UPDATE 選
項,OPEN 語句還將鎖定資料庫表中游標結果集合對應的資料行。
格式:OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];
3.提取遊標
就是檢索結果集合中的資料行,放入指定的輸出變數中。
格式:FETCH cursor_name INTO {variable_list | record_variable };
執行 FETCH 語句時,每次返回一個數據行,然後自動將遊標移動指向下一個資料行。當
檢索到最後一行資料時,如果再次執行 FETCH 語句,將操作失敗,並將遊標屬性
%NOTFOUND 置為 TRUE。所以每次執行完 FETCH 語句後,檢查遊標屬性%NOTFOUND
就可以判斷 FETCH 語句是否執行成功並返回一個數據行,以便確定是否給對應的變數賦了
值。
4.關閉遊標
當提取和處理完遊標結果集合資料後,應及時關閉遊標,以釋放該遊標所佔
用的系統資源,並使該遊標的工作區變成無效,不能再使用 FETCH 語句取其中資料。
關閉後的遊標可以使用 OPEN 語句重新開啟。
格式:CLOSE cursor_name;
注意:定義的遊標不能有 INTO 子句。
遊標屬性
遊標屬性 屬性作用
Cursor_name%FOUND 布林型屬性,當最近一次提取遊標操作 FETCH成功則為 TRUE,否則為 FALSE;
Cursor_name%NOTFOUND 布林型屬性,與%FOUND 相反;
Cursor_name%ISOPEN 布林型屬性,當遊標已開啟時返回 TRUE;
Cursor_name%ROWCOUNT 數字型屬性,返回已從遊標中讀取的記錄數。
2.2使用案例
--普通遊標
declare
cursor emp_cursor1 is
select ename,sal from emp where sal < 1000;
v_name emp.ename%type;
v_sal emp.sal%type;
begin
open emp_cursor1;
loop
fetch emp_cursor1
into v_name,v_sal;
exit when emp_cursor1%notfound;
dbms_output.put_line(v_name || '---' || v_sal);
--dbms_output.put_line('isOpen:'||emp_cursor1%isopen); --檢視遊標狀態
end loop;
close emp_cursor1;
end;
--遊標傳參
declare
cursor emp_cursor2(cursor_sal number default 2000) is --(此處的引數是預設引數,後面可以重新設定,此預設值失效)
select ename,sal from emp where sal >= cursor_sal;
v_name emp.ename%type;
v_sal emp.sal%type;
begin
open emp_cursor2(cursor_sal=>3000); --(重新設定引數值)
loop
fetch emp_cursor2
into v_name,v_sal;
exit when emp_cursor2%notfound;
dbms_output.put_line(v_name || '---' || v_sal);
end loop;
dbms_output.put_line('rowcount:'||emp_cursor2%rowcount); --(遊標記錄數)
close emp_cursor2;
end;
--if...then(給工資低於2000的員工加薪1元)
declare
cursor emp_cursor3 is
select ename, sal, empno from emp;
v_no emp.empno%type;
v_name emp.ename%type;
v_sal emp.sal%type;
begin
open emp_cursor3;
loop
fetch emp_cursor3
into v_name, v_sal, v_no;
exit when emp_cursor3%notfound;
if v_sal <= 2000 then
update emp set sal = sal + 1 where empno = v_no;
dbms_output.put_line(v_name || '---' || v_sal);
end if;
end loop;
dbms_output.put_line('rowcount:' || emp_cursor3%rowcount);
close emp_cursor3;
end;
--有引數有返回值的遊標(記錄型別)
declare
type emp_record_type is record(
v_no emp.empno%type,
v_name emp.ename%type,
v_sal emp.sal%type);
v_emp_record emp_record_type;
cursor emp_cursor4(dept_no number) return emp_record_type is
select empno, ename, sal from emp where deptno = dept_no;
begin
open emp_cursor4(dept_no=>20);
loop
fetch emp_cursor4
into v_emp_record;
if emp_cursor4%found then
dbms_output.put_line(v_emp_record.v_name || '---' ||
v_emp_record.v_sal);
else
dbms_output.put_line('已經處理完結果集');
exit;
end if;
end loop;
close emp_cursor4;
end;
--for迴圈格式遊標
declare
cursor emp_cursor5 is
select ename, sal from emp;
begin
for v_sal in emp_cursor5 loop
dbms_output.put_line(v_sal.ename || '--***--' || v_sal.sal);
end loop;
end;
--for迴圈格式遊標帶引數
declare
cursor emp_cursor5(dept_no number) is
select ename, sal from emp where deptno=dept_no;
begin
for v_sal in emp_cursor5(30) loop
dbms_output.put_line(v_sal.ename || '--***--' || v_sal.sal);
end loop;
end;
--for迴圈子查詢方式遊標
begin
for v_sal in (select ename, sal from emp where deptno=20) loop
dbms_output.put_line(v_sal.ename || '--***--' || v_sal.sal);
end loop;
end;