【问题标题】:SQL Server: Can Merge Insert Conditionally or Update a Source Table?SQL Server:可以有条件地合并插入或更新源表吗?
【发布时间】:2014-11-14 14:20:34
【问题描述】:

我正在使用 SQL Server 2008 并在两个表之间同步数据,如下所示:

    MERGE into Stock as Target
    using StockHistory as Source on Target.SrNo = Source.SrNo
    When Matched then
            # Update record to target table
    When Not Matched then
            # Insert record to target table
    When Not Matched By Source Then
            # Update Source Table - Current Record

问题1:我想有条件地插入记录“当不匹配时”触发。 例如如果源表列refSrNo_StockCompany 为空,则不应插入目标。

问题 2:如果目标表 "Stock" 与源不匹配 "When Not Matched By Source Then" 触发,它应该更新源表 --> IsSoldOut = 'Yes'。

请建议我如何实现这一目标。

谢谢

【问题讨论】:

  • A MERGE(很像 INSERTUPDATEDELETE)只能影响 single 表中的行 - 你不能让它更改为 TargetSource
  • 只是好奇,在你的代码中,“When Not Matched By Source”条件会被执行吗?因为它是“When Not Matched”的子集,所以它总是先运行它。
  • 是 xbb,如果目标不满足给定条件的源,它将触发...

标签: sql-server tsql


【解决方案1】:

对于问题 1:只需在 WHEN NOT MATCHED 子句中添加一个 AND 条件即可:

WHEN NOT MATCHED AND Source.[refSrNo_StockCompany] IS NOT NULL THEN
    # Insert record to target table

对于问题2:它不能直接完成,因为只能修改TARGET表。但是,它可以在第二步中间接完成。诀窍是使用OUTPUT 子句将已更新的记录捕获到临时表中(并且,我们不使用$action 来区分INSERT 和UPDATE,而是从deleted 表中获取,根据定义,永远不会在 INSERT 操作中填充)。然后,在对源表执行 UPDATE 以过滤掉该列表中的任何内容时,将该列表用作 JOIN。临时表中的记录是匹配后不需要更新的记录。源表中 not 在该临时表中的任何记录都表示将在 WHEN NOT MATCHED BY SOURCE 条件下匹配的所有记录。当然,通过WHEN NOT MATCHED 子句插入的记录都将在临时表中显示为NULL 记录(因为deleted 表中没有任何内容可用于INSERT 操作),并且可以轻松过滤掉这些记录的更新。

-- do this before the MERGE
CREATE TABLE #UpdatedRecords (SrNo INT);

BEGIN TRY
  BEGIN TRAN;

  MERGE ...
  -- add this to the end of the MERGE query
  OUTPUT DELETED.SrNo
  INTO  #UpdatedRecords (SrNo);

  -- optionally do this after the MERGE
  DELETE upd
  FROM   #UpdatedRecords upd
  WHERE  upd.SrNo IS NULL;

  -- do this after the MERGE
  UPDATE sh
  SET    sh.IsSoldOut = 'Yes'
  FROM StockHistory sh
  WHERE NOT EXISTS (
          SELECT upd.SrNo
          FROM   #UpdatedRecords upd
          WHERE  upd.SrNo = sh.SrNo
       );

  COMMIT TRAN;

END TRY
BEGIN CATCH
  ROLLBACK TRAN;
  DECLARE @Error NVARCHAR(4000) = ERROR_MESSAGE();
  RAISERROR(@Error, 16, 1);
END CATCH;

如果您想确保这两个语句作为单个操作的一致性,就像使用 MERGE 时一样(如果它有效),那么将 MERGEUPDATE 包装在 BEGIN TRAN 和 @ 中987654335@.

【讨论】:

  • 谢谢你 Srutzky,Q1 根据给定的建议解决。所以我们可以按照你的建议提供额外的条件......嗯谢谢好友。
  • 嗨,Srutzky,我的 Q2 也解决了,您的技巧非常有效,谢谢.. :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-29
  • 2011-12-10
  • 2014-01-03
相关资源
最近更新 更多