1. 程式人生 > >SQL Server 遊標

SQL Server 遊標

遊標的概念

對錶進行操作的SQL語句通常產生一組記錄,但是許多應用程式,尤其是嵌入SQL語句,不能把整個結果集作為一個單元處理,因此需要一種機制來集中處理某一行或幾行(類似於c語言中的指標),遊標由此而生。

遊標的應用分為五步

1.宣告遊標

T-SQL中宣告遊標使用DECLARE CURSOR語句,格式如下:

DECLARE <NAME> CURSOR
[LOCAL|GLOBAL]   --作用域
[FORWORD_ONLY|SCROLL]  --遊標移動方向
[STATIC|KEYSET|DYNAMIC|FAST_FORWARD]  --遊標型別
[READ_ONLY|SCROLL_LOCKS|OPTIMISTIC]  --訪問屬性
[TYPE_WARNING]  --型別轉換警告
FOR <SELECT ..>
[FOR UPDATE[OF<列名>[,...n]]]  --可修改的列
  • LOCAL | GLOBAL 分別宣告區域性, 全域性遊標。
  • FORWORD_ONLY   宣告的遊標只支援FETCH的NEXT選項,而SCROLL支援NEXT,  PRIOR,  FIRST,  LAST, RELATIVE,ABSOLUTE選項。
  • STATIC(靜態遊標)當遊標開啟(不是宣告)時,將建立該遊標使用的資料的臨時複本。 對遊標的所有請求都從 tempdb 中的這一臨時表中得到應答; 因此,在對該遊標進行提取操作時返回的資料中不反映對基表所做的修改,並且該遊標不允許修改。
  • KEYSET(鍵集驅動遊標)當遊標開啟時,遊標中行的成員身份和順序已經固定。對行進行唯一標識的鍵集內建在 tempdb
    內一個稱為 keyset 的表中,可以修改表中的非關鍵字列的值,但不能插入資料。
  • DYNAMIC(動態遊標)反映在滾動遊標時對結果集內的各行所做的所有資料更改。 行的資料值、順序和成員身份在每次提取時都會更改。動態遊標不支援 absolute 提取選項。 
  • FAST_FORWARD(快速只進遊標)對資料的修改在提取遊標時可立即反映出來(在 SQL Server 2000 中,FAST_FORWARD 和 FORWARD_ONLY 遊標選項是互相排斥的。 如果指定了二者,則會引發錯誤。在 SQL Server 2005 及更高版本中,這兩個關鍵字可以用在同一個 DECLARE CURSOR 語句中
  • 若遊標沒有指定任何訪問或型別引數,則預設為全域性、只進、動態遊標。(這是在SQLServer2008 R2上的測試結果,具體取決於軟體設定  
  • READ_ONLY說明遊標為只讀的。   SCROLL_LOCKS 說明通過遊標進行的定位更新或刪除一定會成功。將行讀入遊標時 SQL Server 將鎖定這些行,以確保隨後可對它們進行修改。 如果還指定了FAST_FORWARD或STATIC,則不能指定SCROLL_LOCKS。  OPTIMISTIC指定如果行自讀入遊標以來已得到更新,則通過遊標進行的定位更新或定位刪除不成功 ,如果還指定了FAST_FORWARD,則不能指定OPTIMISTIC。
  • TYPE_WARNING 指定將遊標從所請求的型別隱式轉換為另一種型別時向客戶端傳送警告訊息。

例:

DECLARE CUR1 CURSOR
SCROLL
DYNAMIC
SELECT 編號,姓名
    FROM LIST
    WHERE 性別 = '男'
FOR UPDATE OF 聯絡電話

2.開啟遊標

在T-SQ中使用OPEN語句:

OPEN {{[GLOBAL] <CURSOR NAME>}|@<CURSOR VARIABLE NAME>}
  • 如果使用GLOBAL,說明打開了全域性變數,否則為區域性變數。
  • 開啟遊標後,可以使用全域性變數@@CURSOR_ROWS檢視遊標中資料行的數目。當值為0時,表示沒有遊標開啟,當值為-1時,代表遊標時動態的,當值為n時,代表遊標已被填充,n為具體資料行數。

例:

DECLARE CUR1 CURSOR
SCROLL
SCROLL_LOCKS
SELECT 編號,姓名
    FROM LIST
    WHERE 性別 = '男'
FOR UPDATE OF 聯絡電話
 
OPEN CUR1
SELECT '資料行數' = @@CURSOR_ROWS

3.讀取遊標

FETCH語句格式:

FETCH 
          [ [ NEXT | PRIOR | FIRST | LAST 
                    | ABSOLUTE { n | @nvar } 
                    | RELATIVE { n | @nvar } 
               ] 
               FROM 
          ] 
{ { [ GLOBAL ] cursor_name } | @cursor_variable_name } 
[ INTO @variable_name [ ,...n ] ] --into說明將讀取的遊標資料存放到指定的變數中

-fetch first:提取遊標的第一行。

--fetch next:提取上次提取的行的下一行。

--fetch prior:提取上次提取的行的前一行。

--fetch last:提取遊標中的最後一行。

--fetch absolute n:

-- 如果n 為正整數,則提取 遊標中的第n行

-- 如果n為負整數,則提取遊標最後一行之前的第n行

-- 如果n 為0,則不提取任何行

--fetch relative n :

-- 如果n為正,則提取上次提取的行之後的第n行。

-- 如果n為負,則提取上次提取的行之前的第n行。

-- 如果n為0,則再次提取同一行

@@fetch_status儲存fetch語句的狀態。  0 :fetch語句成功     -1:fetch語句失敗或行不在結果集中   -2: 提取的行不存在

例:

FETCH RELATIVE 3 FROM LIST
SELECT 'FETCH執行狀況' = @@FETCH_STATUS

4.關閉遊標

CLOSE {{[GLOBAL] <CURSOR NAME>}|@<CURSOR VARIABLE NAME>}

5.釋放遊標

DEALLOCATE {{[GLOBAL] <CURSOR NAME>}|@<CURSOR VARIABLE NAME>}

//  參考:心存善念的博文