SQL Server遊標

什麼是遊標

結果集,結果集就是select查詢以後返回的全部行數據的集合。sql

遊標則是處理結果集的一種機制吧,它能夠定位到結果集中的某一行,多數據進行讀寫,也能夠移動遊標定位到你所須要的行中進行操做數據。數據庫

通常複雜的存儲過程,都會有遊標的出現,他的用處主要有:性能優化

  1. 定位到結果集中的某一行。
  2. 對當前位置的數據進行讀寫。
  3. 能夠對結果集中的數據單獨操做,而不是整行執行相同的操做。
  4. 是面向集合的數據庫管理系統和麪向行的程序設計之間的橋樑。

遊標的分類

根據遊標檢測結果集變化的能力和消耗資源的狀況不一樣,SQL Server支持的API服務器遊標分爲一下4種:服務器

  • 靜態遊標: 靜態遊標的結果集,在遊標打開的時候創建在TempDB中,不論你在操做遊標的時候,如何操做數據庫,遊標中的數據集都不會變。例如你在遊標打開的時候,對遊標查詢的數據表數據進行增刪改,操做以後,靜態遊標中select的數據依舊顯示的爲沒有操做以前的數據。若是想與操做以後的數據一致,則從新關閉打開遊標便可。
  • 動態遊標:這個則與靜態遊標相對,滾動遊標時,動態遊標反應結果集中的全部更改。結果集中的行數據值、順序和成員在每次提取時都會變化。全部用戶作的增刪改語句經過遊標都可見。若是使用API函數或T-SQL Where Current of子句經過遊標進行更新,他們將當即可見。在遊標外部所作的更新直到提交時纔可見。
  • 只進遊標:只進遊標不支持滾動,只支持從頭至尾順序提取數據,數據庫執行增刪改,在提取時是可見的,但因爲該遊標只能進不能向後滾動,因此在行提取後對行作增刪改是不可見的。
  • 鍵集驅動遊標:打開鍵集驅動遊標時,該有表中的各個成員身份和順序是固定的。打開遊標時,結果集這些行數據被一組惟一標識符標識,被標識的列作刪改時,用戶滾動遊標是可見的,若是沒被標識的列增該,則不可見,好比insert一條數據,是不可見的,若可見,須關閉從新打開遊標。

靜態遊標在滾動時檢測不到表數據變化,但消耗的資源相對不多。動態遊標在滾動時能檢測到全部表數據變化,但消耗的資源卻較多。鍵集驅動遊標則處於他們中間,因此根據需求創建適合本身的遊標,避免資源浪費。。函數

遊標的生命週期

遊標的生命週期包含有五個階段:聲明遊標、打開遊標、讀取遊標數據、關閉遊標、釋放遊標。sqlserver

 1.聲明遊標,語法性能

DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] 
     [ FORWARD_ONLY | SCROLL ] 
     [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] 
     [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] 
     [ TYPE_WARNING ] 
     FOR select_statement 
     [ FOR UPDATE [ OF column_name [ ,...n ] ] ]

參數說明:fetch

  • cursor_name:遊標名稱。
  • Local:做用域爲局部,只在定義它的批處理,存儲過程或觸發器中有效。
  • Global:做用域爲全局,由鏈接執行的任何存儲過程或批處理中,均可以引用該遊標。
  • [Local | Global]:默認爲local。
  • Forward_Only:指定遊標智能從第一行滾到最後一行。Fetch Next是惟一支持的提取選項。若是在指定Forward_Only是不指定Static、KeySet、Dynamic關鍵字,默認爲Dynamic遊標。若是Forward_Only和Scroll沒有指定,Static、KeySet、Dynamic遊標默認爲Scroll,Fast_Forward默認爲Forward_Only
  • Static:靜態遊標
  • KeySet:鍵集遊標
  • Dynamic:動態遊標,不支持Absolute提取選項
  • Fast_Forward:指定啓用了性能優化的Forward_Only、Read_Only遊標。若是指定啦Scroll或For_Update,就不能指定他啦。
  • Read_Only:不能經過遊標對數據進行刪改。
  • Scroll_Locks:將行讀入遊標是,鎖定這些行,確保刪除或更新必定會成功。若是指定啦Fast_Forward或Static,就不能指定他啦。
  • Optimistic:指定若是行自讀入遊標以來已獲得更新,則經過遊標進行的定位更新或定位刪除不成功。當將行讀入遊標時,sqlserver不鎖定行,它改用timestamp列值的比較結果來肯定行讀入遊標後是否發生了修改,若是表不行timestamp列,它改用校驗和值進行肯定。若是已修改改行,則嘗試進行的定位更新或刪除將失敗。若是指定啦Fast_Forward,則不能指定他。
  • Type_Warning:指定將遊標從所請求的類型隱式轉換爲另外一種類型時向客戶端發送警告信息。
  • For Update[of column_name ,....] :定義遊標中可更新的列。

2.聲明一個動態遊標優化

declare orderNum_02_cursor cursor scroll
for select OrderId from bigorder where orderNum='ZEORD003402'

3.打開遊標spa

--打開遊標語法
open [ Global ] cursor_name | cursor_variable_name

cursor_name:遊標名,cursor_variable_name:遊標變量名稱,該變量引用了一個遊標。

--打開遊標
open orderNum_02_cursor

4.提取數據

--提取遊標語法
Fetch
[ [Next|prior|Frist|Last|Absoute n|Relative n ]
from ]
[Global] cursor_name
[into @variable_name[,....]]

參數說明:

  • Frist:結果集的第一行
  • Prior:當前位置的上一行
  • Next:當前位置的下一行
  • Last:最後一行
  • Absoute n:從遊標的第一行開始數,第n行。
  • Relative n:從當前位置數,第n行。
  • Into @variable_name[,...] : 將提取到的數據存放到變量variable_name中。

例子:

--提取數據
fetch first from orderNum_02_cursor
fetch relative 3 from orderNum_02_cursor
fetch next from orderNum_02_cursor
fetch absolute 4 from orderNum_02_cursor
fetch next from orderNum_02_cursor
fetch last from orderNum_02_cursor 
fetch prior from orderNum_02_cursor
select * from bigorder where orderNum='ZEORD003402'

結果(對比一下,就明白啦):

例子:

--提取數據賦值給變量
declare @OrderId int
fetch absolute 3 from orderNum_02_cursor into @OrderId
select @OrderId as id
select * from bigorder where orderNum='ZEORD003402'

結果:

經過檢測全局變量@@Fetch_Status的值,得到提取狀態信息,該狀態用於判斷Fetch語句返回數據的有效性。當執行一條Fetch語句以後,@@Fetch_Status可能出現3種值:0,Fetch語句成功。-1:Fetch語句失敗或行不在結果集中。-2:提取的行不存在。

這個狀態值能夠幫你判斷提取數據的成功與否。

declare @OrderId int
fetch absolute 3 from orderNum_02_cursor into @OrderId
while @@fetch_status=0  --提取成功,進行下一條數據的提取操做
 begin
   select @OrderId as id
   fetch  next from orderNum_02_cursor into @OrderId  --移動遊標
 end 

5.利用遊標更新刪除數據 

--遊標修改當前數據語法
Update 基表名 Set 列名=[,...] Where Current of 遊標名
--遊標刪除當前數據語法
Delete 基表名  Where Current of 遊標名
---遊標更新刪除當前數據
---1.聲明遊標
declare orderNum_03_cursor cursor scroll
for select OrderId ,userId from bigorder where orderNum='ZEORD003402'
--2.打開遊標
open orderNum_03_cursor
--3.聲明遊標提取數據所要存放的變量
declare @OrderId int ,@userId varchar(15)
--4.定位遊標到哪一行
fetch First from orderNum_03_cursor into @OrderId,@userId  --into的變量數量必須與遊標查詢結果集的列數相同
while @@fetch_status=0  --提取成功,進行下一條數據的提取操做 
 begin
   if @OrderId=122182
     begin
     Update bigorder Set UserId='123' Where Current of  orderNum_03_cursor  --修改當前行
     end
   if @OrderId=154074
      begin
      Delete bigorder Where Current of  orderNum_03_cursor  --刪除當前行
      end
   fetch next from orderNum_03_cursor into @OrderId ,@userId  --移動遊標
 end  

6.關閉遊標

 遊標打開後,服務器會專門爲遊標分配必定的內存空間存放遊標操做的數據結果集,同時使用遊標也會對某些數據進行封鎖。因此遊標一旦用過,應及時關閉,避免服務器資源浪費。

--關閉遊標語法
close [ Global ] cursor_name | cursor_variable_name
--關閉遊標
close orderNum_03_cursor

7.刪除遊標

刪除遊標,釋放資源

--釋放遊標語法
deallocate  [ Global ] cursor_name | cursor_variable_name
--釋放遊標
deallocate orderNum_03_cursor
相關文章
相關標籤/搜索