MERGE查询和删除记录

Not*_*tMe 28 t-sql sql-server merge sql-server-2008-r2

我有一个看起来像这样的表:

AccountID, ItemID
1, 100
1, 200
2, 300
Run Code Online (Sandbox Code Playgroud)

我有一个proc接受一个表值参数,该参数更新与帐户关联的项目.我们将传递以下内容:

AccountID, ItemID
3, 100
3, 200
Run Code Online (Sandbox Code Playgroud)

proc类似于:

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
Run Code Online (Sandbox Code Playgroud)

根据传入的数据,我希望它能在表中添加2条新记录.

我想要的是有一个WHEN NOT MATCHED BY SOURCE子句,它将删除不匹配的指定帐户的项目.

例如,如果我通过

AccountID, ItemID
1, 100
1, 400
Run Code Online (Sandbox Code Playgroud)

然后我希望它删除1,200的记录; 但是留下所有其他人.

如果我这样做:

WHEN NOT MATCHED BY SOURCE THEN
  DELETE;
Run Code Online (Sandbox Code Playgroud)

然后它将删除未引用的帐户的所有记录(即:帐户ID 2和3).

我怎样才能做到这一点?

谢谢,

Mar*_*ith 44

我可以想到两种显而易见的方法,但它们都涉及再次处理TVP.

首先是改变DELETE条件

    WHEN NOT MATCHED BY SOURCE 
    AND target.AccountId IN(SELECT AccountId FROM @Items) THEN
        DELETE;
Run Code Online (Sandbox Code Playgroud)

第二种是使用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;
Run Code Online (Sandbox Code Playgroud)

  • 花了一段时间才回到这一点。DELETE 条件的第一个选项效果很好。谢谢, (2认同)

小智 6

希望这可以帮助。

--  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;
Run Code Online (Sandbox Code Playgroud)


小智 5

在sql数据库中创建表类型变量

CREATE TYPE [dbo].[YourTableType] AS TABLE(
     [AccountID] [int] NULL,
     [ItemID] [int] NULL
     )
   GO
Run Code Online (Sandbox Code Playgroud)

更改您的更新程序

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;
Run Code Online (Sandbox Code Playgroud)

结尾