使用带有WHERE条件的OUTPUT的MERGE语句

时间:2016-05-18 14:15:08

标签: sql sql-server

我试图将数据从一个系统插入到另一个系统中,因此我保留了一个中间映射表,以保持旧表和新表的ID。

我使用MERGE条件,有没有办法

DECLARE @TenantId INT = 1

MERGE dbo.[Account] AS t
USING (SELECT  m.[AccountId],
               m.[TenantId],
               a.[ID_Account],
               a.[Account_No],
               a.[Account_Name],               
          FROM [Client1].dbo.[Account] a
          LEFT JOIN migration.[Account] m ON m.[ID_Account] = a.[ID_Account] AND m.[TenantId] = @TenantId
      ) AS s
ON (t.[AccountId] = s.[AccountId] AND t.[TenantId] = s.[TenantId]) 

WHEN NOT MATCHED THEN
    INSERT ([TenantId], [Number], [Name], [Active] )
    VALUES (@TenantId, s.[Account_No], s.[Account_Name], 1)
    OUTPUT @TenantId, inserted.[AccountId], s.[ID_Account] INTO migration.[Account];

这很好,但是如果我再次尝试运行它,则会在我的迁移中再次插入记录。[Account]表保留重复数据。有没有办法在输出中放置where条件?

2 个答案:

答案 0 :(得分:0)

您要做的是在匹配时进行更新:

MERGE into dbo.[Account] AS destination
USING (SELECT  m.[AccountId],
               m.[TenantId],
               a.[ID_Account],
               a.[Account_No],
               a.[Account_Name],               
          FROM [Client1].dbo.[Account] a
          LEFT JOIN migration.[Account] m ON m.[ID_Account] = a.[ID_Account] AND m.[TenantId] = @TenantId
      ) AS holdinarea
ON (destination.[AccountId] = holdinarea.[AccountId] AND destination.[TenantId] = holdinarea.[TenantId]) 
WHEN  MATCHED THEN
    UPDATE set [AccountId]=holdinarea.accountid,
               [TenantId]=holdinarea.tenantID
WHEN NOT MATCHED THEN
    INSERT ([TenantId], [Number], [Name], [Active] )
    VALUES (holdingarea.TenantId, holdingarea.[Account_No], holdingarea.[Account_Name], 1);

答案 1 :(得分:0)

当您检查目标中是否存在来自源的值时,您将检查来自migration.Account的AccountId是否等于来自dbo.Account的AccountId。您将结果输出到迁移表,但原始记录仍然存在,因此它将包含在后续的合并执行中。

要解决您的问题,您需要:

  • 删除原始记录
  • 在插入后更新的迁移表中添加isUpdated列,将阻止加载源。
  • 使用新的AccountId更新AccountId,以便它与后续执行的条件相匹配。
  • 让新记录以某种方式取消源记录中的原始记录。

这是一个使用新的isUpdated并更新accountId列的方法:

UPDATE m SET
  isUpdated = 1,
  AccountId = o.NewAccountId
FROM migration.Account [m]
INNER JOIN (
    MERGE dbo.[Account] AS t
    USING (SELECT  m.[AccountId],
                   m.[TenantId],
                   a.[ID_Account],
                   a.[Account_No],
                   a.[Account_Name],               
              FROM [Client1].dbo.[Account] a
              LEFT JOIN migration.[Account] m ON m.[ID_Account] = a.[ID_Account] 
                   AND m.[TenantId] = @TenantId
              WHERE m.isUpdated IS NULL OR m.isUpdated = 0
          ) AS s
    ON (t.[AccountId] = s.[AccountId] AND t.[TenantId] = s.[TenantId]) 

    WHEN NOT MATCHED THEN
        INSERT ([TenantId], [Number], [Name], [Active] )
        VALUES (@TenantId, s.[Account_No], s.[Account_Name], 1)
        OUTPUT @TenantId, s.AccountId [OriginalAccountId], inserted.[NewAccountId]
) [o] ON o.TenantId = m.TenantId AND o.OriginalAccountId = m.AccountId