1. 程式人生 > >oracle儲存過程----遊標(cursor)的學習

oracle儲存過程----遊標(cursor)的學習

oracle儲存過程—-遊標(cursor)的學習

  今天又學了一個新的概念Cursor ,即遊標。
  接上一篇,oracle儲存過程—-儲存過程執行簡單的增刪改查sql ,上一篇中,寫到儲存過程的查詢sql ,當時在寫到查詢的時候,忽然不知道怎麼對查詢結果是多條的資料,如何操作遍歷呢。

遊標(Cursor)的定義與作用

  遊標是SQL的一個記憶體工作區,由系統或使用者以變數的形式定義。遊標的作用就是用於臨時儲存從資料庫中提取的資料塊。在某些情況下,需要把資料從存放在磁碟的表中調到計算機記憶體中進行處理,最後將處理結果顯示出來或最終寫回資料庫。這樣資料處理的速度才會提高,否則頻繁的磁碟資料交換會降低效率。
  不過我是新手,我理解的是,遊標就像我們查詢資料返回的集合型別,比如List

,我就把它當做一個引用型別,它指向了記憶體區域中的資料結果集

遊標(Cursor)的應用場景

  就以我現在理解的來說,遊標既然像查詢結果集list ,那使用cursor 的情況,肯定會有下邊這兩種情況,才可能使用到cursor

  1. 需要依據查詢到的結果集,作為條件,進行下一步的查詢。
  2. 需要在結果集某個位置上,滿足某種條件時,對資料進行不同的修改。
遊標(Cursor)的使用考慮

  上邊的兩種情況,都會涉及到遍歷資料(儲存過程 裡如何遍歷資料,下一篇再寫),所以遊標的使用也需要注意:

  • 比如,你的查詢結果集很大,首先佔了很多的記憶體,其次,遍歷這麼龐大的結果集,效率也肯定高不了。
  • 另外,如果還有其他方式解決問題的話,那就不要選擇使用遊標(網上搜來的),我沒測試過效率,但是遊標在使用中,的確有,定義遊標、開啟遊標、關閉遊標,這些操作,這樣也肯定快不了多少。
遊標(Cursor)的類別

  遊標有兩種,顯示遊標隱式遊標

隱式遊標
  上一篇中用到的SELECT…INTO…查詢語句,一次只能從資料庫中提取一行資料,對於這種形式的查詢和DML操作,系統都會使用一個隱式遊標。
DML操作和單行SELECT語句會使用隱式遊標,它們是:

  • 插入操作:INSERT。
  • 更新操作:UPDATE。
  • 刪除操作:DELETE。
  • 單行查詢操作:SELECT … INTO …。

  (2018-08-19補充)當然,隱式遊標還有一種寫法,如下,並沒有定義遊標:

create or replace procedure test_cryptic_procedure
as
begin
for cryptic_rec in (
  select * from ly_ds
)
loop
dbms_output.put_line('名稱:'||cryptic_rec.ly_mc||' 年齡:'||cryptic_rec.ly_nl);
end loop;
end;

  如下方式執行:

set serveroutput on;
begin
 test_cryptic_procedure;
end;

  將會看到如下的結果:

匿名塊已完成
名稱:eee 年齡:23
名稱:王五 年齡:22
名稱:趙六六 年齡:29
名稱:李四 年齡:20

  提示一下:因為隱式遊標預設開啟遊標,但是如果呼叫%ISOPEN 卻返回false 。這個注意一下,如果還沒懂%ISOPEN 啥意思,那暫且不要管這個提示了。

顯式遊標
  顯示遊標還分為靜態遊標動態遊標 。顯示遊標的寫法會在儲存過程中定義Cursor ,並且一般都有固定的四個步驟:宣告遊標開啟遊標提取資料關閉遊標 。顯式遊標開啟後,必須顯式地關閉。遊標一旦關閉,遊標佔用的資源就被釋放,遊標變成無效,必須重新開啟才能使用。
  隱式遊標其實預設已經開啟遊標,並在執行完成後關閉遊標釋放資源。
 &ems;如果你想詳細瞭解一下遊標的概念 ,我是參考了下邊這兩篇文章:

遊標(Cursor)的例子

  下邊是我學習後寫的第一個遊標的例子。不像上邊那個隱式遊標的例子連遊標都沒有定義,下邊這個是定義了遊標,但是沒有去開啟,for 迴圈會預設開啟遊標的。

create or replace procedure test_select3_procedure
(sex  varchar)
AS
--遊標的定義
Cursor test_cursor is
select id,ly_mc,LY_NB,ly_nl from ly_ds where LY_NB=sex;
cur test_cursor%rowtype;  --遊標的型別,我理解類似於list的泛型
BEGIN
for cur in test_cursor loop
exit when test_cursor%notfound;
dbms_output.put_line('資料是:'||cur.id||'_'||cur.ly_mc||'_'||cur.LY_NB||'_'||cur.ly_nl);
end loop;
END;

  上邊,首先看Cursor test_cursor is 這一行,它的意思是定義一個遊標,test_cursor 為你要定義的名字,而is 後邊是一個sql,也就是說當前這個sql的查詢結果,賦值給遊標test_cursor
  然後,往下,接著cur test_cursor%rowtype ,這個是定義了一個型別,而這個型別,即是遊標test_cursor 的返回結果型別,型別的名字為cur 。有點類似於java語言List 集合中的一個泛型
  另外,關於for 是一個迴圈的寫法,for cur in test_cursor ,即,從遊標test_cursor 中取出一個結果cur
  還有,注意,loopend loop 這是一個迴圈的開始標誌和結束標誌,但它倆兄弟是一個很執著的迴圈,如果沒有定義退出條件,永遠不會退出的,所以在上邊的迴圈裡邊,有了退出條件exit when test_cursor%notfound; ,即當遊標test_cursor 中沒有資料了,就退出迴圈。
  當然loop 迴圈的退出,發生下邊的情況,才能退出:

  1. 有exit,並滿足條件後退出。
  2. loop中丟擲了異常。
  3. 存在goto 標識。

  最後,可能大家注意到,上邊並沒有顯示遊標中一定有的四個步驟,
宣告遊標開啟遊標提取資料關閉遊標 ,那是因為for 迴圈這樣的遍歷會自動給我們開啟遊標,並在結束後關閉遊標,下邊會學習其他的遍歷方法,但是都沒有for 這樣智慧,所以覺得for 循環遊標,是個很好的選擇。

  執行上邊的儲存過程:
set serveroutput on;
execute test_select3_procedure('女');

  會得到如下的遍歷結果,正是我根據條件查詢到的結果集。

PROCEDURE TEST_SELECT3_PROCEDURE 已編譯
匿名塊已完成
資料是:2_王五_女_22
資料是:3_趙六六_女_29
資料是:4_李四_女_20