Sql-Server

如果在游標循環中更新數據集引用的表之一,游標的源數據集是否會在每次迭代時更新?

  • February 7, 2020

在這個例子中:

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;

引用自:https://dba.stackexchange.com/questions/259179