遊標(cursor)--顯式遊標&隱式遊標、遊標四個屬性、循環遍歷

https://blog.csdn.net/qq_36743482/article/details/79354036java

1.1 cursor是什麼
cursor是光標,遊標的意思。好比咱們的鼠標的光標就是cursor。
那麼在數據庫中cursor是什麼呢?
當運行DML(select,update,insert,delete)語句時,ORACLE會在內存中爲其分配緩衝區(Context Area),PL/SQL打開一個內建遊標並處理結果,遊標是維護查詢結果的內存中的一個區域。
遊標在運行DML語句時打開,完成後關閉。
通俗的說:
咱們知道,select語句會產生一個結果集,而遊標是指在這個結果集上的第一條記錄的一個指針。
而咱們每次取出(fetch)一條記錄,cursor就會自動指向下一條記錄。
若是學過Java的話,能夠這樣理解,cursor相似於Java中的迭代器iterator。







數據庫

1.2 cursor做用
基於以上的理解,cursor天然就被用於:取出每一條記錄,遍歷結果集。
編程

1.3 cursor的四個屬性
cursor有以下四個屬性:
函數

%isopen:布爾類型。判斷遊標是否打開,打開爲true。對於隱式遊標而言,這個值老是false,由於隱式遊標在DML語句執行時打開,結束時就當即關閉。
%found:布爾類型。在執行任何DML語句前SQL%FOUND和SQL%NOTFOUND的值都是NULL。在執行DML語句後,SQL%FOUND的屬性值將是:
oop

  . TRUE :INSERT
  . TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE.
  . TRUE :SELECT INTO至少返回一行

測試

%notfound:布爾類型。當SQL%FOUND爲TRUE時,SQL%NOTFOUND爲FALSEfetch

%rowcount:數值類型。在執行任何DML語句以前,SQL%ROWCOUNT的值都是NULL,對於SELECT INTO語句,若是執行成功,SQL%ROWCOUNT的值爲1,若是沒有成功,SQL%ROWCOUNT的值爲0,同時產生一個異常NO_DATA_FOUND。
注:PLSQL中的布爾類型的值爲null、true、false。
.net

2.顯式遊標和隱式遊標
在遊標聲明以前,咱們來看下顯式遊標和隱式遊標。
命令行

2.1 隱式遊標
事實上,當咱們在PLSQL中進行非查詢(或者返回單條記錄的查詢)語句,如update、delete、insert等時,ORACLE 系統會自動地爲這些操做設置遊標並建立其工做區,而且隱式遊標的名字爲SQL,由ORACLE 系統定義。
對於隱式遊標的操做,如定義、打開、取值及關閉操做,都由ORACLE 系統自動地完成,無需用戶進行處理。
PL/SQL管理隱式遊標,當查詢開始時隱式遊標打開,查詢結束時隱式遊標自動關閉。
用戶只能經過隱式遊標的相關屬性,來完成相應的操做。在隱式遊標的工做區中,所存放的數據是與用戶自定義的顯示遊標無關的、最新處理的一條SQL 語句所包含的數據。
簡單實例
對於以下一張表ljb_test,更新每一個人的薪水:





指針


set serveroutput on;
begin
update ljb_test set salary = salary + 1;
dbms_output.put_line('更新了'||SQL%rowcount||'行數據'); --must before commit
commit;
end;
/
1
2
3
4
5
6
7
結果以下:















這裏須要指出的是:關於隱式遊標的屬性操做,必須在commit以前,能夠嘗試把打印輸出放在commit以後,獲得的結果是0。這裏之因此結果加了2,是由於我實驗了兩次。

2.2 顯式遊標
當查詢返回結果超過一行時,就須要一個顯式遊標,此時用戶不能使用select into語句。
顯式遊標在PL/SQL塊的聲明部分聲明,在執行部分或異常處理部分打開,取數據,關閉。
這裏要作一個聲明,咱們所說的遊標一般是指顯式遊標,而顯式遊標須要被聲明。


2.2.1 cursor的聲明、打開、關閉、從遊標提取數據
聲明遊標

CURSOR cursor_name IS select_statement;
1
打開遊標

OPEN cursor_name;
1
關閉遊標

CLOSE cursor_name;
1
從遊標提取數據
從遊標獲得一行數據使用FETCH命令。每一次提取數據後,遊標都指向結果集的下一行。
語法以下:



FETCH cursor_name INTO variable[,variable,...]
1
如:

set serveroutput on;
declare
cursor c is select * from ljb_test; --1.聲明遊標的時候Oracle不會從數據庫中取數據
v_test c%rowtype;
begin
open c; --2.打開遊標,此時從數據庫中取數據,並把結果集放在內存中
fetch c into v_test; --3.獲取數據,fetch的時候遊標自動往下移動一格
dbms_output.put_line(v_test.name);






fetch c into v_test;
dbms_output.put_line(v_test.name);
close c; --4.關閉遊標,清掉內存。成對編程
end;
/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
命令行運行,結果以下:



















2.2.2 遍歷結果集
若是咱們想要遍歷整個測試表,顯然須要經過循環來進行。
正常狀況下若是遵循循環遍歷遊標應當聽從如下步驟:
一、打開遊標
二、開始循環
三、從遊標中取值
四、檢查那一行被返回
五、處理
六、關閉循環
七、關閉遊標
事實上,咱們確實能夠經過該方式實現,即經過while循環和do while循環。
可是,for循環卻不無需這麼複雜,這裏咱們重點介紹for循環。
上文提到,PLSQL中有三種循環,這裏須要指出的是,使用遊標遍歷時,最簡單最穩定的就是for循環,但另外兩種循環仍然會作簡單介紹。以下:












2.2.2.1 for循環遍歷
FOR循環的遊標按照正常的聲明方式聲明,可是不須要顯式的打開、關閉、取數據,測試數據的存在、定義存放數據的變量等等。
for循環是最簡單也是最不容易出錯的方式,推薦採用for循環遍歷。

set serveroutput on;
declare
cursor c is select * from ljb_test;
--無需在此聲明變量v_test
begin
--無需顯式打開遊標
for v_test in c loop
--無需顯式fetch
dbms_output.put_line(c%rowcount||'--'||v_test.name);
end loop;
--無需顯式關閉遊標
end;
/
1
2
3
4
5
6
7
8
9
10
11
12
13
九條記錄所有被打印,運行結果以下:


























2.2.2.2 while循環遍歷
declare
cursor c is select * from ljb_test; --聲明遊標的時候Oracle不會從數據庫中取數據
v_test c%rowtype;
begin
open c; --打開遊標,此時從數據庫中取數據,並把結果集放在內存中





fetch c into v_test; --獲取數據,fetch的時候遊標自動往下移動一格
while c%found loop
dbms_output.put_line(c%rowcount||'--'||v_test.name);
fetch c into v_test;
end loop;
close c; --關閉遊標,清掉內存。成對編程
end;
/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
九條記錄被遍歷,結果以下:






















若是咱們把fetch語句和打印語句調換一下位置,結果會怎樣?


能夠看到,第一個記錄被跳過取,最後一個打印兩邊。緣由是,咱們第一次打印前fetch了兩次,而最後一個雖然c沒法fetch到數據,可是上一個的c%fetch仍然是true。

因此,採用while循環必定注意fetch和打印的順序。do while相似。

2.2.2.3 do while循環遍歷
declare
cursor c is select * from ljb_test; --聲明遊標的時候Oracle不會從數據庫中取數據
v_test c%rowtype;
begin
open c;
loop
fetch c into v_test;
exit when(c%notfound);
dbms_output.put_line(c%rowcount||'--'||v_test.name); --若是順序反了,就會最後一條記錄打印兩次
end loop;
close c; --關閉遊標,清掉內存。成對編程
end;
/
1
2
3
4
5
6
7
8
9
10
11
12
13


























2.2.3 含參遊標
相似於函數,咱們能夠將參數傳遞給遊標並在查詢中使用。

CURSOR cursor_name[(parameter[,parameter],...)]
IS select_statement;
1
2
參數定義方式爲:



Parameter_name [IN] data_type[{:=|DEFAULT} value]
1
須要注意的是:遊標只能接受傳遞的值,而不能返回值。參數只定義數據類型,沒有大小。

declare
cursor c(v_dep ljb_test.dep%type, v_salary ljb_test.salary%type)
is select * from ljb_test where dep = v_dep and salary = v_salary;
begin
for v_temp in c(3,4000) loop
dbms_output.put_line(v_temp.name);
end loop;
end;
/
1
2
3
4
5
6
7
8
9
結果以下:


















2.4 可更新遊標
declare
cursor c is select * from ljb_test for update; --添加for update便可
begin
for v_temp in c loop
if(v_temp.salary<3500) then
update ljb_test set salary = salary * 2 where current of c; --更新條件
elsif(v_temp = 5000) then
delete from ljb_test where current of c; --更新條件
end if;
end loop;
commit;
end;
/
1
2
3
4
5
6
7
8
9
10
11
12
13
14



























————————————————版權聲明:本文爲CSDN博主「劉金寶_Arvin」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/qq_36743482/java/article/details/79354036

相關文章
相關標籤/搜索