SQL Server 游標


游標(Cursor)是SQL Server的一種數據訪問機制,它使得程序可以逐行處理數據,即允許用戶訪問單獨的數據行,對每一行數據進行單獨的處理。

一,創建游標對象

創建游標對象,注意不是游標變量,游標名稱不需要帶前導@:

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

在創建游標時,需要配置游標的選項,從定義游標的語法中,可以看出,游標共有5個選項。

1,游標的作用域

LOCAL 和 GLOBAL用於定義游標對象的作用域,

  • LOCAL指定游標的作用域是本地,默認值是LOCAL。
  • GLOBAL指定游標的作用域是全局的。

GLOBAL游標的作用域是連接,由連接內的batch或存儲過程中引用,GLOBAL 游標僅在連接斷開時被釋放。

2,游標滾動的方向

FORWARD_ONLY 和 SCROLL用於指定游標滾動的方向:

  • FORWARD_ONLY 指定游標只能向前移動,即只能從第一行滾動到最后一行。FETCH NEXT 語句是唯一受支持的提取方法。
  • SCROLL 指定游標可以向前或向后滾動,

默認情況下,游標是FORWARD_ONLY(僅向前游標),只向前滾動。注意,向前一行是指下一行,向后一行是指上一行。當設置游標為FORWARD_ONLY和DYNAMIC時,游標在處理當前行時會檢測到所有更改,這意味着對數據提交的任何修改操作(INSERT,UPDATE和DELETE)都會影響到獲取的數據集,進而影響到FETCH NEXT語句。由於游標無法向后滾動,在某一行之后,上N行的數據修改無法查看,但是可以通過fetch查看下N行的數據修改。

3,游標是否對數據的修改可見

STATIC 指定靜態游標,靜態游標始終是只讀的,在第一次打開游標時,在tempdb上創建游標的完整結果集,從臨時表來響應游標的查詢操作,因此對基表的修改操作,不會影響游標的結果集。在游標關閉之前,游標的結果集保持不變。

DYNAMIC 指定靜態游標,動態游標反映結果集中的所有修改操作。結果集中的行數據值、順序和成員在每次提取時都會改變。所有用戶做的全部UPDATE、INSERT和DELETE語句均通過游標可見。

FAST_FORWARD 指定啟動了性能優化的FORWARD_ONLY、READ_ONLY游標。如果指定了SCROLL或FOR_UPDATE,則不能指定FAST_FORWARD。

KEYSET 指定游標按照鍵集來滾動,游標的結果集(result set)包含兩部分:鍵+其他列,鍵用於唯一標識一行數據,這意味着鍵(key)是由唯一標識數據行的一列或多列構成的,鍵集(KyeSet)是指由一組鍵構成的集合。

在打開游標時,SQL Server在tempdb中創建臨時表keyset,該表是只讀的,游標的滾動是通過keyset來迭代的。因此,當游標打開時,行的順序已經固定。在游標滾動時,按照鍵集對游標的結果集進行join,返回完整的一行數據。

獲取由鍵集驅動的游標時:

  • 當一個數據行被刪除時,其key仍然存在於臨時表keyset中,但是不再存在於結果集(result set)中。對該key進行fetch操作,@@FETCH_STATUS返回 -2
  • 當插入一個新的數據行時,如果插入操作發生在游標作用域之外,那么插入的數據對當前游標不可見;如果插入操作發生在游標作用域之內,那么插入的數據存在於結果集的末尾。
  • 更新鍵值的操作,等價於先刪除舊的數據行,再插入一個新的數據行。

4,游標是否只讀,是否支持定位修改

READ_ONLY 指定游標是只讀的,不能通過游標修改數據。

SCROLL_LOCKS 指定通過游標進行的定位更新或刪除一定會成功,當把行讀入游標時,SQL Server將鎖定這些行,以確保隨后可對它們進行修改,如果還指定了FAST_FORWARD或STATIC,則不能指定SCROLL_LOCKS。

OPTIMISTIC 指定當行被讀入游標之后,如果數據行被修改了,那么通過游標進行的定位更新或定位刪除不成功。

當將行讀入游標后,SQL Server不鎖定行,SQL Server 通過以下兩種方式來檢測數據行是否被修改:

  • SQL Server使用表的timestamp列值的比較結果來確定行在讀入游標后是否發生了變化。
  • 如果基表不包含timestamp列,SQL Server使用列值得校驗和來檢測當前行得數據值是否被修改。

如果檢測到該行被修改,那么嘗試進行的定位更新或刪除將失敗。如果還指定了FAST_FORWARD,則不能指定OPTIMISTIC。

5,是否通過游標更新數據

FOR UPDATE [OF column_name [,...n]] 用於在游標中定義可以更新的列,如果提供了  [OF column_name [,...n]] 選項,那么僅允許修改列出的列。如果僅指定了FOR UPDATE子句,那么可以修改所有的列。

二,獲取數據和獲取的狀態

通過FETCH命令來獲取游標中的結果集,並把獲取的一行數據的各列賦值給變量列表:

FETCH  [ NEXT | PRIOR | FIRST | LAST   
            | ABSOLUTE { n | @nvar }   
            | RELATIVE { n | @nvar }   
        ]   
FROM { { [ GLOBAL ] cursor_name } | @cursor_variable_name }   
[ INTO @variable_name [ ,...n ] ]  

在賦值時,變量列表 一 一 對應SELECT 子句的字段列表,FETCH 子句可以通過以下選項來設置獲取一行數據的方向:

  • NEXT:表示獲取下一行,
  • PRIOR:表示獲取上一行,
  • FIRST:表示獲取第一行,
  • LAST:表示獲取最后一行
  • ABSOLUTE n:表示獲取從第一行開始的第n行,n表示第n行的絕對位置,
  • RELATIVE n:表示獲取從當前行開始的第n行,n表示第n行的相對位置,

獲取數據行時,是否獲取成功,可以通過全局變量@@FETCH_STATUS來檢測,注意,全局變量的作用域是當前的連接:

@@FETCH_STATUS  

該全局變量返回當前連接中打開的任何游標發出的最后一個FETCH語句的狀態,狀態值是整數:

注意,由於@@FETCH_STATUS 用於檢測當前連接上的所有游標對象的狀態,在使用時,要謹慎。在執行FETCH語句后,必須立即對@@FETCH_STATUS進行測試,然后再對其他游標執行任何其他FETCH語句。

三,舉個例子

下面的腳本,定義了一個靜態的只讀游標,演示了游標打開、遍歷和關閉的全過程:

declare @v1 int 
declare @v2 int

declare cursor_name cursor 
    forward_only static read_only
for
select c1,c2 from table_name;

open cursor_name

fetch next from cursor_name 
into @v1, @v2

while @@fetch_status=0
begin
    -- do something

    fetch next from cursor_name 
    into @v1, @v2
end

close cursor_name
deallocate cursor_name

 

 

參考文檔:

DECLARE CURSOR (Transact-SQL)

SQL Server基礎之游標


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM