私はバッチ処理の挿入ステートメントを書いていて、自分でアイテムをループして挿入された各行に対してSCOPE_IDENTITY()を呼び出す代わりに、一時テーブルを使用して挿入されたIDを追跡したいと考えています。
挿入する必要があるデータには(一時的な)IDがあり、これを別のテーブルにも挿入する必要がある他のデータにリンクしているため、実際のIDと一時IDの相互参照が必要です。
これは私がこれまでに持っているものの例です:
-- The existing table
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX));
-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');
DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);
INSERT INTO @MyTable ( [Name] )
OUTPUT Inserted.ID, INS.ID INTO @MyCrossRef
SELECT [NAME] FROM @MyInsertData INS
-- Check the result
SELECT * FROM @MyCrossRef
問題は、OUTPUT INTO句を取得してIDを受け入れることができないことです。@MyInsertData.ID
と、テーブルをそれ自体に結合する他のトリックを試しましたが、何も機能しないようです。
実際には、INSERT
をMERGE
に変更することで同じことを実現できます。 MERGE
ステートメントは、実際にはSQL Serverで「アップサート」を実行するための非常に優れた方法ですが、挿入する目的でのみ使用するのを妨げるものは何もありません。
-- The existing table
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX));
-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');
DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);
MERGE INTO @MyTable AS dest
USING @MyInsertData AS ins ON 1=0 -- always false
WHEN NOT MATCHED BY TARGET -- happens for every row, because 1 is never 0
THEN INSERT ([Name])
VALUES (ins.[NAME])
OUTPUT inserted.ID, ins.ID
INTO @MyCrossRef (NewId, OldId);
-- Check the result
SELECT * FROM @MyCrossRef
MERGE
の良い点の1つは、ソース列だけでなく、inserted
句の組み込みdeleted
およびOUTPUT
テーブルにもアクセスできることです。 。
実際にテストしていないため、コードにエラーが含まれている可能性があります。 私のブログ投稿 数年前から、クエリのパフォーマンスを含め、もう少し詳しく説明しています。
出力句は、ターゲット行と定数/変数のデータにのみアクセスできます。トリガーで操作している場合のように、ソースSELECT
の他の場所のデータにはアクセスできません。
https://docs.Microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql 状態:
変更されるテーブルの列への参照は、INSERTEDまたはDELETEDプレフィックスで修飾する必要があります。
したがって、元のIDを取得するには、次のように、出力句がエコーバックできるように、宛先テーブルに含める必要があります。
-- The existing table
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX), SourceID INT);
-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');
DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);
INSERT INTO @MyTable ( [Name], SourceID )
OUTPUT Inserted.ID, Inserted.SourceID INTO @MyCrossRef
SELECT [NAME], ID FROM @MyInsertData INS
-- Check the result
SELECT * FROM @MyCrossRef
ただし、ターゲットオブジェクトのスキーマを変更することは、状況によっては実用的でない場合があるため、適用できない場合があります。