web-dev-qa-db-ja.com

カーソルループ内でデータセットが参照するテーブルの1つを更新している場合、カーソルのソースデータセットは反復ごとに更新されますか?

この例では:

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を使用するデータセットが変更されます。

2
J.D.

つまり、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;
2
Randi Vertongen