MERGE Query and deleting records

merge, sql-server, sql-server-2008-r2, t-sql

Solution

I can think of two obvious ways but both of them involve processing the TVP again.

The first is simply to change the `DELETE` condition

    WHEN NOT MATCHED BY SOURCE 
    AND target.AccountId IN(SELECT AccountId FROM @Items) THEN
        DELETE;

The second is to use a CTE to restrict the target

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;

Problem

I have a table that looks something like: ``` AccountID, ItemID 1, 100 1, 200 2, 300 ``` I have a proc that accepts a table value parameter which updates the Items associated with an account. We'll pass something like the following: ``` AccountID, ItemID 3, 100 3, 200 ``` The proc looks something like: ``` 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 ``` Based on the passed in data I expect it to add 2 new records to the table, which it does. What I want is to have a WHEN NOT MATCHED BY SOURCE clause which will remove items for the specified account that aren't matched. For example, if I pass ``` AccountID, ItemID 1, 100 1, 400 ``` Then I want it to delete the record having 1, 200; but leave ALL of the others. If I just do: ``` WHEN NOT MATCHED BY SOURCE THEN DELETE; ``` then it will remove all records for accounts not referenced (ie: account ids 2 and 3). How can I do this? Thanks,

Original source