Oracle系列:Cursor
1,什么是游標?
①從表中檢索出結果集,從中每次指向一條記錄進行交互的機制。
②關系數據庫中的操作是在完整的行集合上執行的。
由 SELECT 語句返回的行集合包括滿足該語句的 WHERE 子句所列條件的所有行。由該語句返回完整的行集合叫做結果集。
應用程序,尤其是互動和在線應用程序,把完整的結果集作為一個單元處理並不總是有效的。
這些應用程序需要一種機制來一次處理一行或連續的幾行。而游標是對提供這一機制的結果集的擴展。
游標是通過游標庫來實現的。游標庫是常常作為數據庫系統或數據訪問 API 的一部分而得以實現的軟件,
用來管理從數據源返回的數據的屬性(結果集)。這些屬性包括並發管理、在結果集中的位置、返回的行數,
以及是否能夠在結果集中向前和/或向后移動(可滾動性)。
游標跟蹤結果集中的位置,並允許對結果集逐行執行多個操作,在這個過程中可能返回至原始表,也可能不返回至原始表。
換句話說,游標從概念上講基於數據庫的表返回結果集。
由於它指示結果集中的當前位置 ,就像計算機屏幕上的光標指示當前位置一樣,“游標”由此得名。
2,游標有什么作用?
①指定結果集中特定行的位置。
②基於當前的結果集位置檢索一行或連續的幾行。
③在結果集的當前位置修改行中的數據。
④對其他用戶所做的數據更改定義不同的敏感性級別。
⑤可以以編程的方式訪問數據庫。
3,為什么避免使用游標?
①在創建游標時,最需要考慮的事情是,“是否有辦法避免使用游標?”
因為游標的效率較差,如果游標操作的數據超過1萬行,那么就應該改寫;
如果使用了游標,就要盡量避免在游標循環中再進行表連接的操作。
4,Oracle游標的類型?
①靜態游標:結果集已經確實(靜態定義)的游標。分為隱式和顯示游標。
⑴隱式游標:所有DML語句為隱式游標,通過隱式游標屬性可以獲取SQL語句信息。
⑵顯示游標:用戶顯示聲明的游標,即指定結果集。當查詢返回結果超過一行時,就需要一個顯式游標。
②REF游標:動態關聯結果集的臨時對象。
5,Oracle游標的狀態有哪些,怎么使用游標屬性?
①游標的狀態是通過屬性來表示。
%Found :Fetch語句(獲取記錄)執行情況 True or False。
%NotFound : 最后一條記錄是否提取出 True or False。
%ISOpen : 游標是否打開True or False。
%RowCount :游標當前提取的行數 。
②使用游標的屬性。
例子:/* conn scott/tiger */
Begin
Update emp Set SAL = SAL + 0.1 Where JOB = 'CLERK';
If SQL%Found Then
DBMS_OUTPUT.PUT_LINE('已經更新!');
Else
DBMS_OUTPUT.PUT_LINE('更新失敗!');
End If;
End;
6,如何使用顯示游標,?如何遍歷循環游標?
①使用顯示游標
⑴聲明游標:划分存儲區域,注意此時並沒有執行Select 語句。
CURSOR 游標名( 參數 列表) [返回值類型] IS Select 語句;
⑵打開游標:執行Select 語句,獲得結果集存儲到游標中,此時游標指向結果集頭, 而不是第一條記錄。
Open 游標名( 參數 列表);
⑶獲取記錄:移動游標取一條記錄
Fetch 游標名 InTo 臨時記錄或屬性類型變量;
⑷關閉游標:將游標放入緩沖池中,沒有完全釋放資源。可重新打開。
Close 游標名;
②遍歷循環游標
⑴For 循環游標
循環游標隱式打開游標,自動滾動獲取一條記錄,並自動創建臨時記錄類型變量存儲記錄。處理完后自動關閉游標。
For 變量名 In 游標名
Loop
數據處理語句;
End Loop;
⑵Loop循環游標
。。。
Loop
Fatch 游標名 InTo 臨時記錄或屬性類型變量;
Exit When 游標名%NotFound;
End Loop;
。。。
例子1:
/* conn scott/tiger */
Declare
Cursor myCur is select empno,ename,sal from emp;
vna varchar2(10);
vno number(4);
vsal number(7,2);
Begin
open myCur;
fetch myCur into vno,vna,vsal;
dbms_output.put_line(vno||' '||vna||' '||vsal);
close myCur;
End;
/
例子2:使用loop遍歷游標。
/* conn scott/tiger */
Declare
Cursor myCur is select ename,job,sal,empno from emp;
varE myCur%rowType;
Begin
if myCur%isopen = false then
open myCur;
dbms_output.put_line('Opening...');
end if;
loop
fetch myCur into varE;
exit when myCur%notfound;
dbms_output.put_line(myCur%rowCount||' '||vare.empno||' '||vare.ename||' '||vare.sal);
end loop;
if myCur%isopen then
Close myCur;
dbms_output.put_line('Closing...');
end if;
End;
/
例子3:使用For循環遍歷游標,
/* conn scott/tiger */
Declare
Cursor myCur is select * from emp;
Begin
for varA in myCur
loop
dbms_output.put_line(myCur%rowCount||' '||varA.empno||' '||varA.ename||' '||varA.sal);
end loop;
End;
/
7,怎樣更新和刪除顯示游標中的記錄?
①UPDATE或DELETE語句中的WHERE CURRENT OF子串專門處理要執行UPDATE或DELETE操作的表中取出的最近的數據。
要使用這個方法,在聲明游標時必須使用FOR UPDATE子串,當對話使用FOR UPDATE子串打開一個游標時,
所有返回集中的數據行都將處於行級(ROW-LEVEL)獨占式鎖定,其他對象只能查詢這些數據行,
不能進行UPDATE、DELETE或SELECT...FOR UPDATE操作。
在多表查詢中,使用OF子句來鎖定特定的表,如果忽略了OF子句,那么所有表中選擇的數據行都將被鎖定。
如果這些數據行已經被其他會話鎖定,那么正常情況下ORACLE將等待,直到數據行解鎖。
②使用更新或刪除:
⑴聲明更新或刪除顯示游標:
Cursor 游標名 IS SELECT 語句 For Update [ Of 更新列列名];
Cursor 游標名 IS SELECT 語句 For Delete [ Of 更新列列名];
⑵使用顯示游標當前記錄來更新或刪除:
Update 表名 SET 更新語句 Where Current Of 游標名;
Delete From 表名 Where Current Of 游標名;
例子1:更新顯示游標記錄
/*conn scott/tiger*/
Declare
Cursor myCur is select job from emp for update;
vjob empa.job%type;
rsal empa.sal%type;
Begin
open myCur;
loop
fetch myCur into vjob;
exit when myCur%notFound;
case (vjob)
when 'ANALYST' then rsal := 0.1;
when 'CLERK' then rsal := 0.2;
when 'MANAGER' then rsal := 0.3;
else
rsal := 0.5;
end case;
update emp set sal = sal + rsal where current of myCur;
end loop;
End;
/
例子2:刪除顯示游標記錄
/*conn scott/tiger
Crate table empa Select * from scott.emp;
*/
Declare
Cursor MyCursor Select JOB From empa For Update;
vSal emp.Sal%TYPE;
Begin
Loop
Fetch MyCursor InTo vSal;
Exit When MyCursor%NotFound;
If vSal < 800 Then
Delete From empa Where Cursor Of MyCursor;
End If;
End Loop;
End;/
8,什么是帶參數的顯示游標?
①與過程和函數相似,可以將參數傳遞給游標並在查詢中使用。
參數只定義數據類型,沒有大小(所有Oracle中的形參只定義數據類型,不指定大小)。
與過程不同的是,游標只能接受傳遞的值,而不能返回值。
可以給參數設定一個缺省值,當沒有參數值傳遞給游標時,就使用缺省值。
游標中定義的參數只是一個占位符,在別處引用該參數不一定可靠。
②使用帶參數的顯示游標
⑴聲明帶參數的顯示游標:
CURSOR 游標名 [(parameter[,parameter],...)] IS Select語句;;
參數形式:1,參數名 數據類型
2,參數名 數據類型 DEFAULT 默認值
例子:
/*conn scott/tiger
Crate table empa Select * from scott.emp;
*/
Declare
Cursor MyCursor(pSal Number Default 800) Select JOB From empa Where SAL > pSal ;
varA MyCursor%ROWTYPE;
Begin
Loop
Fetch MyCursor InTo varA;
Exit When MyCursor%NotFound;
DBMS_OUTPUT.PUT_LINE(MyCursor%RowCount||' '||varA.empno||' '||varA.ename||' '||varA.sal);
End Loop;
End;/
思考:
怎樣將游標作為參數傳遞?
CREATE OR REPLACE procedure(
v_id in table.id%TYPE,
v_name in table.name%TYPE)
is
cursor v_cursor is
SELECT ID, NAME FROM TABLE WHERE ID=v_id AND NAME =v_name;
v1 table%rowtype;
r1 varchar2(100);
begin
OPEN v_cursor;
LOOP
fetch v_cursor into v1;
IF v_cursor%found THEN
IF v1.NAME IS NOT NULL THEN
r1 := '+r1';
END IF;
update table set name = name + r1 where current of v_cursor;
END IF;
END LOOP;
close v_cursor;
END;
我改了下,跑跑試試