【问题标题】:How do I limit the action of an OUTPUT clause in a MERGE statement?如何在 MERGE 语句中限制 OUTPUT 子句的操作?
【发布时间】:2014-02-05 15:29:55
【问题描述】:

这是我的查询:

MERGE INTO [payments_orders] o USING (
    SELECT 1 AS [order_id], 50.00 AS [amount] UNION ALL 
    SELECT 2 AS [order_id], 50.00 AS [amount]
) AS t ([order_id], [amount]) 
ON o.[payment_id] = 4 AND o.[order_id] = t.[order_id] 
WHEN MATCHED THEN UPDATE SET o.[amount] = t.[amount] 
WHEN NOT MATCHED THEN INSERT ([payment_id], [order_id], [amount]) 
VALUES (4, t.[order_id], t.[amount]) 
WHEN NOT MATCHED BY SOURCE AND o.[payment_id] = 4 THEN DELETE 
OUTPUT $ACTION AS [action], [deleted].[order_id];

我正在运行 MERGE 语句来插入或更新哪些订单记录与哪些付款记录相关联以及该付款的分配方式。

我想做的是在末尾添加WHERE $ACTION = 'DELETE';然而那是行不通的。显然你不能在OUTPUT 子句中使用WHERE 子句;那是“不正确的语法”。

如何使该语句输出的唯一行是由DELETE 触发的行?

【问题讨论】:

  • 将它们作为单独的语句保存可能会更好。无论如何,您当前的代码并不能保护您免受并发/竞争条件的影响。 Please read this.
  • @AaronBertrand,谢谢你。我从来没有读过它(反正从来没有使用过 MERGE)

标签: sql sql-server merge


【解决方案1】:

我遇到了同样的问题。到目前为止,我的解决方案(除非我想出另一个解决方案)是将虚拟值插入到临时表中以插入行,然后在合并语句完成后清理表。

CREATE TABLE #deleted_orders (order_id int)

MERGE INTO [payments_orders] o USING (
    SELECT 1 AS [order_id], 50.00 AS [amount] UNION ALL 
    SELECT 2 AS [order_id], 50.00 AS [amount]
) AS t ([order_id], [amount]) 
ON o.[payment_id] = 4 AND o.[order_id] = t.[order_id] 
WHEN MATCHED THEN UPDATE SET o.[amount] = t.[amount] 
WHEN NOT MATCHED THEN INSERT ([payment_id], [order_id], [amount]) 
VALUES (4, t.[order_id], t.[amount]) 
WHEN NOT MATCHED BY SOURCE AND o.[payment_id] = 4 THEN DELETE 
OUTPUT ISNULL([deleted].[order_id], -1) INTO #deleted_orders


DELETE FROM #deleted_orders WHERE order_id=-1

注意:您需要检查性能,并确定此更改是否会对您的用例造成可接受的性能影响。临时表会降低性能:请参阅“临时表”部分here for T-SQL

编辑:实际上我最终做了一些有点不同但非常相似的事情。它为您节省了最后的 DELETE 步骤

INSERT INTO #deleted_orders (order_id)
        SELECT mrg.order_id
        FROM ( MERGE INTO [payments_orders] o USING (
                    SELECT 1 AS [order_id], 50.00 AS [amount] UNION ALL 
                    SELECT 2 AS [order_id], 50.00 AS [amount]
                ) AS t ([order_id], [amount]) 
                ON o.[payment_id] = 4 AND o.[order_id] = t.[order_id] 
                WHEN MATCHED THEN UPDATE SET o.[amount] = t.[amount] 
                WHEN NOT MATCHED THEN INSERT ([payment_id], [order_id], [amount]) 
                VALUES (4, t.[order_id], t.[amount]) 
                WHEN NOT MATCHED BY SOURCE AND o.[payment_id] = 4 THEN DELETE 
                OUTPUT [deleted].[order_id] INTO #deleted_orders
OUTPUT $action as MergeAction, deleted.order_id) AS mrg 
WHERE mrg.MergeAction = 'DELETE'

【讨论】:

  • Wessie,我最终做了与此非常相似的事情。但是,为了避免任何不一致,我只是添加了一个永久表(而不是使用临时表)。
  • @alexwweston,谢谢。我也有类似的问题。请再提出一个后续问题,我正在更新 WHEN MATCHED 和 WHEN NOT MATCHED BY SOURCE 场景的列,无论如何只能捕获 WHEN MATCHED 子句的更新记录。使用 action='UPDATE' 时,我得到了这两个子句的记录。
猜你喜欢
  • 1970-01-01
  • 2012-11-23
  • 2022-07-06
  • 2012-09-14
  • 1970-01-01
  • 2011-09-03
  • 1970-01-01
  • 1970-01-01
  • 2015-10-31
相关资源
最近更新 更多