当不匹配SOURCE时忽略ON滤波器

时间:2014-03-13 14:46:18

标签: sql-server tsql sql-server-2012

我在Web服务中有一个SQL proc,它接受一组用户数据并执行以下操作:

  1. 如果用户不在目的地,请将其插入
  2. 如果用户位于目的地,请使用来自
  3. 的任何新详细信息进行更新
  4. 如果用户在源中不存在,则将其存档在目标
  5. 最后一部分(WHEN NOT MATCHED BY SOURCE THEN UPDATE)存在问题,表中的每一行都更新为archived=1。我假设只有customerId@customerId匹配的行会受到影响,但会更新除ON中匹配的行以外的所有行,并忽略ON过滤器。

    MERGE
        [tbl_Users] AS tgt -- Target
    USING
        #tbl_working AS src -- Source
    ON
        (tgt.customerID = @customerId) AND
        (tgt.employeeID = src.EmployeeId) 
    WHEN MATCHED THEN UPDATE SET -- user exists; update
        tgt.username = src.username
        tgt.name = src.FirstName
    WHEN NOT MATCHED BY TARGET THEN INSERT -- user does not exist; create
        (
        customerID,
        username,
        name
        ) 
        VALUES 
        (
        @customerId,
        src.UserName,
        src.Name
        )
    WHEN NOT MATCHED BY SOURCE THEN UPDATE -- user no longer required; archive
        SET tgt.archived = 1;
    

    我可能没有正确使用最后一部分,所以请欣赏任何输入。

1 个答案:

答案 0 :(得分:2)

您可能只想添加额外条件:

WHEN NOT MATCHED BY SOURCE AND tgt.customerID = @CustomerID
   THEN UPDATE -- user no longer required; archive
        SET tgt.archived = 1;

ON子句仅用于确定sourcetarget的匹配方式。到WHEN ...条款时,它已经完成了它的工作。它并没有留下来并且有选择地适用于其他任何事情。


可能有助于意识到MERGE语句可能会影响target表中的每一行。

让我们说发生的事情是我们将source表拆分为两组行 - sm是通过{target表中的行匹配的行{1}}子句,ONsu中的所有剩余行。

我们还说我们还将source表拆分为两组行 - target是与tm表和source中的行匹配的行是tu中所有剩余的行。

target子句正在处理行集WHEN MATCHEDsm,并确定如何处理这些行。

tm正在处理行WHEN NOT MATCHED IN TARGET

su正在处理行WHEN NOT MATCHED IN SOURCE

您不需要将tu条件添加到AND tgt.customerID = @CustomerID,因为该条件已用于确定WHEN MATCHED中的哪些行以及su中的哪些行}(以及smtu)。

希望在tm子句中有这个额外条件,因为你实际上想要进一步划分WHEN NOT MATCHED集合而不影响所有这些行。


您可能需要考虑的另一个选择是您可以先过滤目标表,然后对其应用合并:

tu

现在上面讨论的关于;WITH CustomerUsers as ( SELECT * FROM tbl_Users where customerID = @customerID ) MERGE CustomerUsers AS tgt -- Target USING #tbl_working AS src -- Source ON (tgt.employeeID = src.EmployeeId) ... 的所有内容实际上只涉及target中属于tbl_Users"

的行的子集