一時テーブルから新しい値を取得し、それらを実際のテーブルにマージして、挿入された行のIDと、その値と一致する既存の行を取得するストアドプロシージャを記述しようとしています。
さて、私が見ているところから見ると、MERGE関数は、間違っている場合を除いて、私がやろうとしていることをサポートしているようには見えません(完全にありそうです、私はSQLの人ではありません-.NET)。とにかく、私は今夜本当にMERGEについて本当に学びました、そして最初は私が使うべきであるように思われました、しかしそれは私が必要とする機能を持っていないようです。残りのストアドプロシージャに必要です。私の主な焦点は、これが機能するかどうかを確認することでしたが、他の問題は、MERGEを介して実行されるストアドプロシージャへの潜在的な同時呼び出しをコードが処理できることを確認する必要があることです。今はそこに閉じ込められていないことはわかっていますが、この時点で機能させるためだけにしようとしていました。だから、私が持っているもの....
DECLARE @Metadata TABLE
(
MetadataId INT PRIMARY KEY IDENTITY(1,1),
MetadataTypeId INT,
MetadataTypeValueId INT
)
INSERT INTO @Metadata
VALUES
(1,23),(2,32),(2,33),(2,43),(1,24),(3,33),(1,20)
--Original Table Data
SELECT * FROM @Metadata
DECLARE @MergeMetadata TABLE
(
MetadataId INT,
MetadataTypeId INT,
MetadataTypeValueId INT
)
INSERT INTO @MergeMetadata (MetadataTypeId, MetadataTypeValueId)
VALUES
(2,32),(2,35),(3,34),(4,1),(1,23)
--Metadata that needs added and/or ID'd if exists
SELECT * FROM @MergeMetadata
DECLARE @FinalMetadata TABLE
(
MetadataId INT,
MetadataTypeId INT,
MetadataTypeValueId INT
)
INSERT INTO @FinalMetadata (MetadataId, MetadataTypeId, MetadataTypeValueId)
VALUES
(2,2,32),(8,2,35),(9,3,34),(10,4,1),(1,1,23)
--This is the same Type/TypeValue Id's from the table above
--However, they've been ID'd with existing IDs from the original table
--Or inserted and ID'd if they didn't exist
--Order doesn't matter for the result, I just need the IDs
SELECT * FROM @FinalMetadata
最初に、一致したときに結果テーブルに挿入し、出力を使用して新しい値を取得することにより、マージによって値を取得しようとしました。
--Try to Insert the existing target when matched into the final table
MERGE @Metadata AS T
USING @MergeMetadata AS S
ON (S.MetadataTypeId = T.MetadataTypeId
AND S.MetadataTypeValueId = T.MetadataTypeValueId)
WHEN MATCHED
THEN --CANT INSERT WHEN MATCHED
INSERT INTO (T.MetadataId, S.MetadataTypeId, S.MetadataTypeValueId) INTO @FinalMetadata
WHEN NOT MATCHED BY TARGET
THEN
INSERT (MetadataTypeId, MetadataTypeValueId)
VALUES (S.MetadataTypeId, S.MetadataTypeValueId)
OUTPUT inserted.MetadataId,
inserted.MetadataTypeId,
inserted.MetadataValueTypeId,
INTO @FinalMetadata
;
次に、OUTPUTを使用して元のIDを取得しようとしました-UPDATEDのプレースホルダーがないことに気付きませんでした:(
--Try to get the original IDs by OUTPUT
MERGE @Metadata AS T
USING @MergeMetadata AS S
ON (S.MetadataTypeId = T.MetadataTypeId
AND S.MetadataTypeValueId = T.MetadataTypeValueId)
WHEN MATCHED
THEN
UPDATE SET (T.MetadataId = T.MetadataId)
WHEN NOT MATCHED BY TARGET
THEN
INSERT (MetadataTypeId, MetadataTypeValueId)
VALUES (S.MetadataTypeId, S.MetadataTypeValueId)
OUTPUT inserted.MetadataId,
updated.MetadataId, --updated isn't a key for OUTPUT
inserted.MetadataValueTypeId,
INTO @FinalMetadata
;
最後に、攻撃計画を元に戻そうとしましたが、ソースの挿入を実行できませんでした
--Try to reverse logic and insert into Source when not matched
MERGE @MergeMetadata T
USING @Metadata S
ON (S.MetadataTypeId = T.MetadataTypeId
AND S.MetadataTypeValueId = T.MetadataTypeValueId)
WHEN MATCHED
THEN UPDATE SET T.MetadataId = S.MetadataId
WHEN NOT MATCHED BY SOURCE
THEN --can't insert in NOT MATCHED BY SOURCE
INSERT (MetadataTypeId, MetadataTypeValueId)
VALUES (T.MetadataTypeId, T.MetadataTypeValueId)
;
長すぎて申し訳ありませんが、私がこれにいくつかの考えと試みをしたことを示したかっただけです。この時点で、代わりにSELECT/IF NOT EXISTS/BEGIN INSERTクラシックロジックを記述する必要がありますか?私がMERGEを読んでいるすべてから、それはこの状況に最適に聞こえましたが、本当に必要なものを私に与えたくないようです。
他のロジックのルートに進む必要がある場合、同時実行で同じDOES NOT EXIST/INSERTが同時に実行されないように、並行性を処理するいくつかの推奨コードのスニペットを提供できますか?
更新はMERGEによって以下を提供することにより追跡されます。
したがって、一致が見つかった場合と、ターゲットによる一致がない場合の両方で、ID列の値は挿入メモリテーブルで使用できます。
MERGEステートメントを使用して1泊の経験で多くのことを行いました!
OUTPUT句のDELETED列のプレフィックスには、MERGE UPDATE SETステートメントで更新された値が含まれている必要があります。これは、試行2で順調に進んでいると思います。