Sql-Server
如果在游標循環中更新數據集引用的表之一,游標的源數據集是否會在每次迭代時更新?
在這個例子中:
DECLARE @KeyField INT, @ValueField INT DECLARE CursorName CURSOR FAST_FORWARD FOR SELECT T1.KeyField, T1.ValueField FROM Table1 AS T1 LEFT JOIN Table2 AS T2 ON T1.ValueField = T2.ValueField WHERE T2.KeyField IS NULL -- Filter out any records that have the same value in T2 as T1 OPEN CursorName FETCH NEXT FROM CursorName INTO @KeyField, @ValueField WHILE (@@FETCH_STATUS = 0) BEGIN INSERT INTO Table2 (KeyField, ValueField) SELECT @KeyField, @ValueField FETCH NEXT FROM CursorName INTO @KeyField, @ValueField END CLOSE CursorName DEALLOCATE CursorName;
(我忘記了我是多麼“喜歡”游標。)
游標循環體內對 Table2 的更新是否會導致在循環的下一次迭代中從數據集中過濾掉該值?…換句話說,更新 Table2 是否會修改使用 Table2 進行原始游標定義的數據集。
換句話說,更新 Table2 是否會修改使用 Table2 進行原始游標定義的數據集。
您正在向其中插入數據,除非您指定關鍵字,否則
table2
這些數據更改可能是可見的。STATIC
指定游標始終按第一次打開游標時的狀態顯示結果集,並製作數據的臨時副本以供游標使用。對游標的所有請求都是從 tempdb 中的這個臨時表應答的
根據游標的聲明,游標可以看到哪些數據還有其他含義。
KEYSET、DYNAMIC、FAST_FORWARD、FORWARD_ONLY等關鍵字會影響此行為。
FORWARD_ONLY文件中的範例
…所有影響結果集中行的目前使用者(或其他使用者送出)的插入、更新和刪除語句在獲取行時都是可見的。但是,因為游標不能向後滾動,所以在獲取行後對數據庫中的行所做的更改通過游標是不可見的……
使用 時
FORWARD_ONLY
,數據是否可見,具體取決於游標所在的行。但是,在您的範例中,由於使用了過濾器:
WHERE T2.KeyField IS NULL -- Filter out any records that have the same value in T2 as T1
即使添加了新行,插入的數據也會被過濾掉,因為非空值被插入到
Table2
.您可以測試您的查詢的這種適應性以創建一個無限循環游標。
DROP TABLE dbo.Table1; DROP TABLE dbo.Table2; CREATE TABLE dbo.Table1(KeyField int,ValueField int); INSERT INTO dbo.Table1 SELECT TOP(10) ROW_NUMBER() OVER( ORDER BY(SELECT NULL)), ROW_NUMBER() OVER( ORDER BY(SELECT NULL)) FROM MASTER..spt_values; CREATE TABLE dbo.Table2(KeyField int,ValueField int) INSERT INTO dbo.Table2 SELECT TOP(10) ROW_NUMBER() OVER( ORDER BY(SELECT NULL)), ROW_NUMBER() OVER( ORDER BY(SELECT NULL)) FROM MASTER..spt_values; DECLARE @KeyField INT, @ValueField INT; DECLARE @counter int = 0; DECLARE CursorName CURSOR FOR SELECT T1.KeyField, T1.ValueField FROM Table1 AS T1 LEFT JOIN Table2 AS T2 ON T1.ValueField = T2.ValueField WHERE T2.KeyField IS NOT NULL; -- CHANGED TO NOT NULL OPEN CursorName FETCH NEXT FROM CursorName INTO @KeyField, @ValueField WHILE (@@FETCH_STATUS = 0) BEGIN INSERT INTO Table2 (KeyField, ValueField) SELECT @KeyField, @ValueField SELECT @KeyField, @ValueField FETCH NEXT FROM CursorName INTO @KeyField, @ValueField SET @counter += 1 END CLOSE CursorName DEALLOCATE CursorName; SELECT @counter;