挿入された行がOUTPUT
ステートメントのUPDATE
から挿入されたときに、挿入された行のID値をどのように取得しますか? _@@IDENTITY
_もSCOPE_IDENTITY()
も正しく設定されていないようです。
このコードを考えてみましょう:
_DECLARE @UpdateTable table (UpdateTableID int IDENTITY, UpdateTableValue int);
DECLARE @InsertTable table (InsertTableID int IDENTITY, UpdateTableValue1 int, UpdateTableValue2 int);
DECLARE @TestValue int = 5;
INSERT INTO @UpdateTable (UpdateTableValue) VALUES (1),(2),(3);
SELECT [@@IDENTITY] = @@IDENTITY, [SCOPE_IDENTITY()] = SCOPE_IDENTITY();
INSERT INTO @InsertTable (UpdateTableValue1, UpdateTableValue2)
SELECT
UpdateTableValue1, UpdateTableValue2
FROM (
UPDATE @UpdateTable
SET UpdateTableValue = UpdateTableValue + @TestValue
OUTPUT deleted.UpdateTableValue, inserted.UpdateTableValue
WHERE UpdateTableID = 2
) AS UpdateResults (UpdateTableValue1, UpdateTableValue2);
SELECT [@@IDENTITY] = @@IDENTITY, [SCOPE_IDENTITY()] = SCOPE_IDENTITY();
_
最後に挿入された行のID値は1ですが、_@@IDENTITY
_およびSCOPE_IDENTITY()
関数は、最後のステートメントが実行される前の元のINSERT
から元の値を返します。
_@@VERSION
_:
Microsoft SQL Azure(RTM)-12.0.2000.8 May 2 2019 20:11:13 Copyright(C)2019 Microsoft Corporation
これは、_@@IDENTITY
_およびSCOPE_IDENTITY()
をUPDATE
ステートメントと組み合わせて使用すると機能しないためと考えられます。これに対する自然な応答は「どうして外側のINSERTのIDを返さないのですか?」答えは、スコープのためです。
UPDATE
ステートメントとINSERT
ステートメント(OUTPUT
の結果を使用)は1つのステートメントとして実行され、本質的に互いに同じスコープ内にあります。エンジンがクエリを実行すると、これが認識されるため、外部のINSERT
によって生成されたIDを追跡できません。これを証明するには、UPDATE
とINSERT
を2つの個別のステートメントに分割する次のクエリを実行します。
_DECLARE @UpdateTable table
(
UpdateTableID int IDENTITY,
UpdateTableValue int
);
DECLARE @InsertTable table
(
InsertTableID int IDENTITY,
UpdateTableValue1 int,
UpdateTableValue2 int
);
DECLARE @TestValue int = 5;
INSERT INTO @UpdateTable (UpdateTableValue)
VALUES (1),(2),(3);
SELECT [@@IDENTITY] = @@IDENTITY, [SCOPE_IDENTITY()] = SCOPE_IDENTITY();
DECLARE @tmp TABLE
(
UpdateTableValue1 int,
UpdateTableValue2 int
);
UPDATE @UpdateTable
SET UpdateTableValue = UpdateTableValue + @TestValue
OUTPUT deleted.UpdateTableValue, inserted.UpdateTableValue
INTO @tmp
WHERE UpdateTableID = 2;
INSERT INTO @InsertTable (UpdateTableValue1, UpdateTableValue2)
SELECT
UpdateTableValue1, UpdateTableValue2
FROM @tmp;
SELECT [@@IDENTITY] = @@IDENTITY, [SCOPE_IDENTITY()] = SCOPE_IDENTITY();
_
正しい結果が得られます:
テーブルからIDを取得する必要がある場合、私が見る限り、3つのオプションがあります。
OUTPUT
句を最後のINSERT
に追加して、生成されたIDを取得します。IDENT_CURRENT()
関数を使用します。(グローバル一時テーブルではなく)一時テーブルを使用している場合、IDENT_CURRENT()
は、セッション内で生成された値のみを返すことを保証できるため、完全に問題ありません(他のセッションではオブジェクトを使用できないため)。 。ただし、指定した例がそれだけの場合は、オプション2を使用して、別のOUTPUT
句を使用して、生成されたID値をキャプチャします。
_INSERT INTO @InsertTable (UpdateTableValue1, UpdateTableValue2)
OUTPUT inserted.InsertTableID
SELECT
UpdateTableValue1, UpdateTableValue2
FROM
(
UPDATE @UpdateTable
SET UpdateTableValue = UpdateTableValue + @TestValue
OUTPUT deleted.UpdateTableValue, inserted.UpdateTableValue
WHERE UpdateTableID = 2
) AS UpdateResults (UpdateTableValue1, UpdateTableValue2);
_
次に、正しい値を出力します。