Question :
In this example:
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;
(I forgot how much I “loved” cursors.)
Would the update to Table2 inside the cursor loop body, cause that value to be filtered out from the dataset on the next iteration of the loop?…in other words does updating Table2 modify the dataset that uses Table2 for the original cursor definition.
Answer :
in other words does updating Table2 modify the dataset that uses
Table2 for the original cursor definition.
You are inserting data into table2
and these data changes could be visible unless you specify the STATIC
keyword.
Specifies that the cursor always displays the result set as it was
when the cursor was first opened, and makes a temporary copy of the
data to be used by the cursor. All requests to the cursor are answered
from this temporary table in tempdb
There are other implications to what data is visible to the cursor depending on the declaration of the cursor.
Keywords such as KEYSET, DYNAMIC, FAST_FORWARD,FORWARD_ONLY impact this behaviour.
An example in the documentation on FORWARD_ONLY
…All insert, update, and delete statements made by the current user (or
committed by other users) that affect rows in the result set are
visible as the rows are fetched. Because the cursor cannot be scrolled
backward, however, changes made to rows in the database after the row
was fetched are not visible through the cursor…
When using FORWARD_ONLY
, data could be visible depending on what row the cursor is located at.
However, in your example, due to the filter used:
WHERE T2.KeyField IS NULL -- Filter out any records that have the same value in T2 as T1
Even if new rows are added, the inserted data will be filtered out as non nulls are inserted into Table2
.
You could test this adaptation of your query to create an endless looping cursor.
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;