這次簡單說說游標的分類。
先看看通常游標的語法
DECLARE cursor_name CURSOR [ LOCAL :局部游標,僅在當前會話有效 | GLOBAL : 全局游標,全局有效,可以 ] [ FORWARD_ONLY :只能向前游標,讀取游標時只能使用 Next 謂詞 | SCROLL :滾動游標,FIRST、LAST、PRIOR、NEXT、RELATIVE、ABSOLUTE 都可以使用 ] [ STATIC :定義一個游標,以創建將由該游標使用的數據的臨時復本。對游標的所有請求都從 tempdb 中的這一臨時表中得到應答; | KEYSET :對基表中的非鍵值所做的更改(由游標所有者更改或由其他用戶提交)可以在用戶滾動游標時看到。其他用戶執行的插入是不可見的(不能通過 Transact-SQL 服務器游標執行插入)。如果刪除某一行,則在嘗試提取該行時返回值為 -2 的 @@FETCH_STATUS。 | DYNAMIC :定義一個游標,以反映在滾動游標時對結果集內的各行所做的所有數據更改。行的數據值、順序和成員身份在每次提取時都會更改。動態游標不支持 ABSOLUTE 提取選項 | FAST_FORWARD :指定啟用了性能優化的 FORWARD_ONLY、READ_ONLY 游標。如果指定了 SCROLL 或 FOR_UPDATE,則不能也指定 FAST_FORWARD ] [ READ_ONLY :只讀游標,不能對游標內容進行更改,不能使用 where current of 語句 | SCROLL_LOCKS :指定通過游標進行的定位更新或刪除一定會成功。將行讀入游標時 SQL Server 將鎖定這些行,以確保隨后可對它們進行修改。 | OPTIMISTIC :指定如果行自讀入游標以來已得到更新,則通過游標進行的定位更新或定位刪除不成功。當將行讀入游標時,SQL Server 不鎖定行
] [ TYPE_WARNING ] FOR select_statement [ FOR UPDATE [ OF column_name [ ,...n ] ] :制定那些列可以進行更新,如果不填,則默認全部可以更新 ]好了,拋完書包之后,現在問題來了,本人盡量圖文并茂的描述每種類型的特點吧……_(:з」∠)_--------------------------------------------------------------我是分割線-----------------------------------------------------------------------------------------------------------------------------------------------測試表的結構
CREATE TABLE [dbo].[Employee]([ID] [int] NOT NULL IDENTITY(1, 1) primary key,[NAME] [nvarchar] (50) NULL,[Name2] [varchar] (50) NULL) ON [PRIMARY]GO
FORWARD_ONLY 和 SCROLL 這兩者在用的過程中還是比較好區別。一個只能前進,一個可以前滾翻后滾翻什么的。先看看
FORWARD_ONLY
DECLARE CR_CURSOR CURSOR FAST_FORWARD --這個游標,是一個只讀游標而已哦~FOR SELECT ID , NAME FROM dbo.Employee WHERE ID >= 24 DECLARE @ID INT , @Name NVARCHAR(50) OPEN CR_CURSORFETCH NEXT FROM CR_CURSOR INTO @ID, @NameWHILE @@FETCH_STATUS = 0 BEGIN --UPDATE dbo.Employee SET Name2 = @Name WHERE CURRENT OF CR_CURSOR 因為是只讀游標,所以是不允許修改游標本身內容 UPDATE dbo.Employee SET Name2 = @Name WHERE ID = @ID FETCH NEXT FROM CR_CURSOR INTO @ID, @Name ENDCLOSE CR_CURSORDEALLOCATE CR_CURSOR
然后我們看看執行計劃,這個就跟普通的即時查詢時沒有任何區別的,所以我猜測,假如在游標讀取過程中,數據發生了變化,是可以獲取出來的。下面我來驗證一下
1、在讀取之前,我先溫柔的刪除Employee 表里面,ID = 25的記錄
DELETE FROM dbo.Employee WHERE ID = 25
2、然后在讀取游標里面開啟單步調試,讀到ID = 24的節點
3、然后在讀下一個游標之前,我添加了一條數據
SET IDENTITY_INSERT Employee ONINSERT INTO dbo.Employee (ID,NAME )VALUES ( 25,N'我是插進來的小三')SET IDENTITY_INSERT Employee OFF
然后繼續F10前進 ~咦~~25出來了野~
證明了,FORWARD_ONLY 這貨是在游標向下滾動的時候即使獲取數據的。所以能捕捉到新插入或刪除的數據。大致是這樣紙了,下面在看看
SCROLL
DECLARE CR_CURSOR CURSOR SCROLL --代碼基本一致,只是換成了 SCROLLFOR SELECT ID , NAME FROM dbo.Employee WHERE ID >= 24 DECLARE @ID INT , @Name NVARCHAR(50) OPEN CR_CURSORFETCH NEXT FROM CR_CURSOR INTO @ID, @NameWHILE @@FETCH_STATUS = 0 BEGIN UPDATE dbo.Employee SET Name2 = @Name WHERE CURRENT OF CR_CURSOR --這句現在可以執行了 FETCH NEXT FROM CR_CURSOR INTO @ID, @Name ENDCLOSE CR_CURSORDEALLOCATE CR_CURSOR
慣例先看看這個執行計劃吧~可以看到有一個查詢過程要把數據插入到 CWT_PrimaryKey 的臨時表里面。那我猜想,如果在游標讀取途中,外部有數據的增加,是獲取不到的了,那如果更新和刪除會怎么樣呢?實驗一下
1、在讀取之前,我還是先溫柔的刪除Employee 表里面,ID = 25的記錄
DELETE FROM dbo.Employee WHERE ID = 25
2、然后在讀取游標里面開啟單步調試,讀到ID = 24的節點
3、然后在讀下一個游標之前,我添加了一條數據
SET IDENTITY_INSERT Employee ONINSERT INTO dbo.Employee (ID,NAME )VALUES ( 25,N'我是插進來的小三')SET IDENTITY_INSERT Employee OFF
然后F10……ID25沒有粗線_(:з」∠)_直接到26去了
確實,外部新增了數據,是獲取不到的。下面測一下修改和刪除。
1、然后在讀取游標里面開啟單步調試,讀到ID = 24的節點
2、修改ID是25的數據
UPDATE dbo.Employee SET NAME = '我是修改了的ID25哦' WHERE ID = 25
3、然后按F10繼續走,是可以獲取的喲~
刪除呢?重試一遍,在單步的過程中直接將 ID = 25的數據抹掉,然后就直接循環結束了~查了一下 @@Fetch_Status = -2 提取數據失敗,當然啦……數據都被刪除了。順帶一提,如果繼續往下取,還是可以取到下一條數據的喲~……圖就不截了。。。
然后在繼續試下各種方式,再進行補充
新聞熱點
疑難解答