次のようなテーブルがあります。
AccountID, ItemID
1, 100
1, 200
2, 300
アカウントに関連付けられたアイテムを更新するテーブル値パラメーターを受け入れるプロシージャがあります。次のようなものを渡します。
AccountID, ItemID
3, 100
3, 200
プロシージャは次のようになります。
procedure dbo.MyProc( @Items as dbo.ItemListTVP READONLY )
AS
BEGIN
MERGE INTO myTable as target
USING @Items
on (Items.AccountId = target.AccountId)
AND (Items.ItemId = target.ItemId)
WHEN NOT MATCHED BY TARGET THEN
INSERT (AccountId, ItemId)
VALUES (Items.AccountId, Items.ItemId)
;
END
渡されたデータに基づいて、テーブルに2つの新しいレコードを追加することを期待しています。
WHEN NOT MATCHED BY SOURCE句を使用して、一致しない項目を削除します指定されたアカウントの場合。
たとえば、私がパスした場合
AccountID, ItemID
1, 100
1, 400
次に、1、200のレコードを削除します。しかし、他のすべてを残します。
私がやった場合:
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
次に、参照されていないアカウント(つまり、アカウントID 2および3)のすべてのレコードを削除します。
これどうやってするの?
おかげで、
私は2つの明白な方法を考えることができますが、どちらもTVPを再度処理する必要があります。
最初は単にDELETE
条件を変更することです
WHEN NOT MATCHED BY SOURCE
AND target.AccountId IN(SELECT AccountId FROM @Items) THEN
DELETE;
2つ目は、CTEを使用してターゲットを制限することです
WITH cte as
(
SELECT ItemId, AccountId
FROM @myTable m
WHERE EXISTS
(SELECT * FROM @Items i WHERE i.AccountId = m.AccountId)
)
MERGE INTO cte as target
USING @Items Items
ON (Items.AccountId = target.AccountId) AND
(Items.ItemId = target.ItemId)
WHEN NOT MATCHED BY TARGET THEN
INSERT (AccountId, ItemId)
VALUES (Items.AccountId, Items.ItemId)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
お役に立てれば。
-- myTable
-- (
-- GroundID bigint, -- FK
-- GroupID, bigint, -- FK
-- AcceptingReservations bit
-- );
merge into myTable as target
using @tmpTable as source
on ( source.GroundID = target.GroundID )
and ( source.GroupID = target.GroupID )
when
not matched by target
then
insert ( GroundID, GroupID, AcceptingReservations )
values
(
source.GroundID,
source.GroupID,
source.AcceptingReservations
)
-- If there is a row that matches, update values;
when matched
then
update set
target.AcceptingReservations = source.AcceptingReservations
-- If they do not match, delete for that GroundID only;
when
not matched by source
and target.GroundID = @GroundID
then
delete;
SQLデータベースにテーブル型変数を作成する
CREATE TYPE [dbo].[YourTableType] AS TABLE(
[AccountID] [int] NULL,
[ItemID] [int] NULL
)
GO
アップデート手順を変更する
ALTER PROCEDURE YourProcedure
@Items YourTableType READONLY
AS
BEGIN
MERGE INTO [dbo].[YourTable] as Target
USING @Items as Source
ON
Target.[AccountID]=Source.[AccountID] and
Target.[ItemID]=Source.[ItemID]
WHEN NOT MATCHED by TARGET THEN
INSERT
([AccountID],
[ItemID])
VALUES
(Source.[AccountID],
Source.[ItemID])
WHEN NOT MATCHED BY SOURCE AND
target.[ItemID] IN(SELECT [ItemID] FROM @Items)
THEN
DELETE;
終わり
上記の回答は、説明されている状況で機能します。
請求書の例外を保存するために使用する例外テーブルがあります。請求書の現在の例外のみを含めます。したがって、請求書データの一部を修正してプロセスを再度実行すると、例外の新しいリストが作成されます。新しい例外を追加し、既存の例外を更新して、もう存在しない例外を削除します-SO同じ請求書に含まれている限り(または何でも)。
私が抱えていた問題は、MERGEステートメントがSOURCE THEN DELETEによって一致しないと、TARGETテーブル内のすべてが削除されることでした。 SOURCEに存在しない追加アイテムだけではありません! WHEN NOT MATCHED BY SOURCEステートメントを修飾できなかったので、DELETEは、SOURCEに存在しなくなったTARGETの同じ請求書番号のみに影響します。
「MERGEステートメントの「WHEN NOT MATCHED BY SOURCE」句ではターゲット列のみが許可されています。」というエラーが表示されました。
したがって、TARGET行を変数で修飾する必要があります。