資料庫:SQLServer中游標的用法筆記

數據庫技術分享社區 發佈 2020-12-14T21:28:04+00:00

一、游標的概念知識游標可以理解為SQL Server的一種數據訪問機制,它允許用戶訪問數據的維度是數據行。用戶可以對每一行數據進行單獨處理,從而降低系統開銷和潛在的阻隔情況,游標主要用於存儲過程,觸發器和 T_SQL複雜的腳本中,它能使查詢結果集的數據用於其它T_SQL語句。

一、游標的概念知識

游標可以理解為SQL Server的一種數據訪問機制,它允許用戶訪問數據的維度是數據行。用戶可以對每一行數據進行單獨處理,從而降低系統開銷和潛在的阻隔情況,

游標主要用於存儲過程,觸發器和 T_SQL複雜的腳本中,它能使查詢結果集的數據用於其它T_SQL語句。在查看或處理結果集中向前或向後瀏覽每一行數據的功能。與C語言中的指針功能有些相似,它可以指向結果集中的任意位置,如果要對結果集進行逐行單獨處理時,必須聲明一個指向該結果集中的游標變量。

SQL Server 中的數據操作結果都是面向集合的,並沒有一種描述表中單一記錄的表達形式,除非使用WHERE子句限定查詢結果,使用游標可以補充這種功能,並且游標的使用和操作過程更加靈活。

游標的生命周期:聲明游標→打開游標→讀取數據→關閉游標→釋放游標。

二、游標的語法格式

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] ] ]

參數說明:

cursor_name:是所定義的游標的名稱。

LOCAL:對於在其中創建批處理、存儲過程或觸發器來說,該游標的作用域是局部的。

GLOBAL:指定該游標的作用域是全局的

FORWARD_ONLY:指定游標只能從第一行滾動到最後一行。FETCH NEXT是唯一支持的數據讀取選項,如果在指定FORWARD_ONLY時不指定STATIC,KEYSET和DYNAMIC關鍵字,則游標作為DYNAMIC游標進行操作,如果FORWARD_ONLY和SCROLL均為指定,則除非指定STATIC,KEYSET和DYNAMIC關鍵字,否則默認為FORWARD_ONLY。STATIC,KEYSET和DYNAMIC游標默認為SCROLL。與ODBC和ADO這類資料庫API不同,STATIC,KEYSET和DYNAMIC T_SQL游標支持FORWARD_ONLY。

STATIC:定義一個游標,以創建將該游標使用的數據臨時複本,對游標的所有請求都從tempdb中的臨時表中不得到應答;因此,在對該游標進行提取操作時返回的數據中不反映對基表所做的修改,並且該游標不允許修改。

KEYSET:指定當游標打開時,游標重複的行的成員身份和順序已經固定。對行進行唯一標識的鍵值內置在tempdb內一個稱為keyset的表中。

DYNAMIC:定義一個游標,以反映在滾動游標時對結果集內的各行所做的所有數據更改。行的數據值、順序和成員身份在每次提取時都會更改,動態游標不支持ABSOLUTE提取選項。

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

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

OPTIMISTIC:指定如果行自讀入游標以來已得到更新,則通過游標進行的定位更新或定位刪除不成功。當將行讀入游標時,SQL Server不鎖定行,它改用timestamp列值比較結果來確定行讀入游標後是否發生了修改,如果表不包含timestamp列,它改用校驗和值進行確定,如果以修改該行,則嘗試進行的定位更新或刪除將失敗,如果還指定了FAST_FORWARD,則不能指定OPTIMISTIC。

TYPE_WARNING:指定游標從所請求的類型隱式轉換為另一種類型時,向客戶端發送警告消息。

select_statement:是定義游標結果集中的標準SELECT語句。

註:DECLARE <游標名>CURSOR FOR 查詢語句; -- 最簡單的游標聲明

注意:關閉游標,需要執行下面兩條命令

CLOSE 游標名稱; --關閉游標

DEALLOCATE 游標名稱;--撤銷游標(釋放資源 )

三、游標主要用途

1、定位到查詢結果集中的某一行。

2、對當前位置的數據進行讀寫。

3、可以對結果集中的數據單獨操作,而不是整行執行相同的操作。

4、游標是面向數據集合和面向數據行的程序設計之間的橋樑。

四、游標的簡單示例

DECLARE @Id NVARCHAR(MAX)
DECLARE @UserName NVARCHAR(MAX)
DECLARE @Password NVARCHAR(MAX)
DECLARE @NickName NVARCHAR(MAX)
create table #tmp (Id NVARCHAR(MAX),UserName NVARCHAR(MAX),Password NVARCHAR(MAX),NickName NVARCHAR(MAX))  --建立臨時數據表

--聲明一個游標mycursor,select語句中參數的個數必須要和從游標取出的變量名相同
DECLARE mycursor CURSOR  
FOR  
    SELECT Id,UserName,Password,NickName FROM dbo.Users
OPEN mycursor  --打開游標
--從游標里取出數據賦值到我們剛才聲明的變量中(移動游標指向到第一條數據,提取第一條數據存放在變量中)
FETCH NEXT FROM mycursor INTO @Id, @UserName,@Password,@NickName        
--判斷游標的狀態
-- 0 fetch語句成功
---1 fetch語句失敗或此行不在結果集中
--- 2 被提取的行不存在
WHILE (@@fetch_status = 0)   --如果上一次操作成功則繼續循環
    BEGIN        
        --顯示出我們每次用游標取出的值
        --print (@Id+'--------'+@UserName+'--------'+@Password+'----'+@NickName)
        --條件判斷
        if (@Id>=10)
        begin
            INSERT INTO #tmp(Id,UserName,Password,NickName) VALUES(@Id,@UserName,@Password,@NickName)
        end
        --用游標去取下一條記錄(繼續取下一行數據)
        FETCH NEXT FROM mycursor INTO @Id,@UserName,@Password,@NickName   
    END
  
CLOSE mycursor --關閉游標
DEALLOCATE mycursor --撤銷游標(釋放資源 )
SELECT * FROM #tmp; --查詢臨時表
DROP TABLE #tmp --刪除臨時表

五、總結

建議儘量避免使用游標,游標使用時會對數據行加鎖,可能會影響其他業務的正常操作。當數據量大時執行效率也較低。另外,系統內存也是其中一個限制。因為游標其實是相當於把磁碟數據整體放入了內存中,如果游標數據量大則會造成內存不足,內存不足帶來的影響大家都知道了。所以,在數據量小比較小的情況才去使用游標。但不建議使用游標,可以通過從程式語言等方式實現相應的業務邏輯。

關鍵字: