一、遇到的問題
實際上,也不算什麼太大的問題O(∩_∩)O:我們有時候可能希望在批次或儲存過程中直接對select結果集進行加工,這個時候,我們需要一種能夠讓我們逐一處理每一行記錄的資料庫物件。
二、遊標的概念
解決上面的問題,我們可以使用一種叫做「遊標」的資料庫物件。
遊標(Cursor) 可以看做一種資料型,它可以用來遍歷結果集,相當於指針,或是數組中的下標。它處理結果集的方法有以下幾種:
定位到結果集的某一行
從當前結果集的位置搜尋一行或一部分行
遊玩使用方法(建立、開啟、讀取、關閉、刪除)
【建立遊標】
和定義各種資料類型的方法有點像,但是注意,不要加「@」(實際上也有「遊標類型的變量”,和“遊標”的用法幾乎完全相同,而且定義時使用@符號)。以下是定義遊標的語句:
declare 遊標名cursor [local|global] [forward_only|scroll]
for
『selectg查詢語句🎀for
〜字,標號查詢不符圖表示全域遊標(預設值,可以省略)。當指定 forward_only(預設值,可以省略)時,遊標是只進的,也就是說只能從頭到尾地提取記錄,如果需要在行之間來回跳躍,需要指定為scroll。
【使用遊標】
只創建遊標但是不使用它,就沒有任何意義了。下面我們先舉個最簡單的例子來示範建立好遊標之後的幾步使用過程:
--【建立好遊標】
declare C1 cursor for select xingming from yiren
『 --【開啟遊標】
open C1
--【讀取遊標】
fetch next from C1 into @xingming --while的特點就是要先寫一次
『 begin print '姓名:'+@xingming fetch next from C1 into @xingming end刪除遊標】
deallocate C1
遊標的使用方法是不是和Java中的whle(rs.next()){}很像呢?實際上rs.next()執行時就直接在結果集中向後移動一條了,如果沒有到達結果集的末端,仍然會執行迴圈體。這裡使用遊標也是一樣,@@FETCH_STATUS的值為0時,遊標尚未走到結尾。當它不為0了,遊標就走到了結尾,將退出循環。
fetch next from 遊標名 into 變數名清單 是一種固定形式的讀取遊標內容的方法。當查詢語句選擇了多個欄位的時候,讀取時也需要藉助這句話來賦值多個變數。於是寫成變數名列表。
【全域遊標與scroll遊標】
前面提到全域遊標和scroll遊標,下面舉個例子:
if(CURSOR_STATUS('global')'CURS_2'cate' are CURSOR_2 cursor scroll --全域的scroll遊標
for select xingming,nicheng,xingbie from yiren
--第一個T-SQL批次開始
『 @xingming varchar(20) ,@nicheng varchar(50),@xingbie nchar set @seq=4 fetch absolute @seq from CURSOR_2 intoq=xingming,@nicheng,@xingbief🜀🜀 begin print '第'+cast(@seq as varchar)+'個藝人是:'+@xingming print case @xingbie when '男' then '他' when '女' then '她' end 暱稱是:'+@nicheng end close CURSOR_2 go 〜+ @seq int, @xingming varchar(20),@ nicheng varchar(50),@xingbie nchar set @seq=5 --分成了兩個批,需要再次定義@seq fetch absolute @seq from CURSOR_2 into @xingming,@nich,fetch absolute @seq from CURSOR_2 into @xing @@FETCH_STATUS=0) begin print '第'+cast(@seq as varchar)+'個藝人是:'+@xingminging ' when約〵print case @xn; ' then '她' end
+'的暱稱是:'+@nicheng
end
close CURSOR_2
close CURSOR_2 deallocate CURSOR_2
當開啟了scroll選項後,fetch可以用來讀next(後移)、prior(前移)、first(第一行)、last(最後一行)、 absolute(以數值定位到絕對行)、relative(以數值定位到相對行) 。
全域遊標一旦被定義就會一直存在,所以每個批次都能看到它。直到使用deallocate來刪除它,它才會消失。 CURSOR_STATUS('global','CURSOR_2')可以檢查它的狀態。
【遊標的巢狀】
由於大大影響系統效能,簡單了解一下即可。
if(CURSOR_STATUS('global','CURSOR_3')!=-3) deallocate CURSOR_3
declare CURSOR_3 cursor for
declare CURSOR_3 cursor for
de _3
declare @ycid int
fetch next from CURSOR_3
into @ycid
into @ycid
while(@@FETCH_STATUS=0)
begin
print '參加第'+cast(@cid yvar
print '參加第'+cast(@cid as 節目的音樂〜 OR_4 cursor for select xingming from yiren where yirenid in (select yirenid from yanchuyiren where yanchuid=@ycid) --這句使用了子查詢,實際上可以再嵌套一個遊標〜 --這句使用了子查詢,實際上可以再嵌套一個遊標 open CURSOR_4
fetch next from CURSOR_4 into @xingming
while(@@FETCH_STATUS=0)
『 _4 into @xingming
end
close CURSOR_4
deallocate CURSOR_4
fetch next from CURSOR_3
into @ycid
print ''
end
『 【遊標變數】
遊標變數是真正的把遊標當作資料型別來使用的一種方法,遊標變數和遊標物件的差別就在於是否有@。建立遊標變數的時候,首先declare @遊標變數名 cursor,然後set @遊標變數名稱=cursorfor select語句。
declare @c1 CURSOR
set @c1=cursor for select xingming from yiren
餺c1 into @xingming
print @xingming
close @c1
deallocate @c1
四、遊標的注意事項
【遊標的缺點】
㟀標使用標價會把結果沒有使用預設結果集的效率高。所以,能不用遊標就盡量不要 用。
【遊標的補充說明】
當我們剛剛打開一個遊標的時候,它並不指向第一筆記錄,而是指向第一筆記錄的前邊。我們可以拿書做比喻,遊標不只可以指向記錄集中的記錄(書 內容的每一頁),也可以指向記錄集外部沒有記錄的地方(書的封面和封底)。
@@fetch_status有3種取值:0表示fetch 正常執行、-1表示fetch超出了結果集、-2表示fetch所指向的行已經不存在了。
五、修改分頁查詢儲存過程,使用遊標
將第一個分支修改成如下代碼:
if @currentpage >1
begin set @currentpage = @totalpages end declare @start int,@count int set @count = 0 set @startcomh_vSv] cursor scroll for select * from ' +@tablename+' order by '+@idname exec(@sql) open cursor_1 〜〦 〦〜,4vvo. etch_status=0 begin set @count = @count+1 fetch next from cursor_1 if @count=@pagesize-1 『『 ate cursor_1 end 並去掉原來go前面的 exec(@sql) 即可。如果不去掉這句,會在預存程序的最後額外再執行一次這句話,從而錯誤地再次產生@cursor_1遊標。