2014-01-16 73 views
2

這裏是我的查詢:如何限制MERGE語句中的OUTPUT子句的操作?

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觸發的?

+1

您可能有更好的運氣保持它們作爲單獨的語句。無論如何,你當前的代碼並不能保護你不受併發/競爭條件的影響。 [請閱讀本文](http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/)。 –

+0

@AaronBertrand,謝謝你。我從來沒有讀過它(從來沒有使用太多MERGE) –

回答

4

我遇到了同樣的問題。到目前爲止,我的解決方案(除非我想出另一個解決方案)是將虛擬值插入到插入行的臨時表中,然後在合併語句完成後清理表。

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' 
+0

Wessie,我最終做了一些非常相似的事情。但是,爲了避免任何不一致,我只是添加了一個永久表(而不是使用臨時表)。 – SoaperGEM