MERGE INTO AS Target
USING AS Source
ON
WHEN MATCHED THEN
WHEN NOT MATCHED BY TARGET THEN
WHEN NOT MATCHED BY SOURCE THEN
OUTPUT $action, inserted.*, deleted.*;
每日依銷售明細扣減庫存,庫存歸零則刪除產品列。
CREATE PROCEDURE Production.usp_UpdateInventory @OrderDate DATETIME
AS
MERGE Production.ProductInventory AS Target
USING (
SELECT ProductID, SUM(OrderQty) AS TotalQty
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
WHERE soh.OrderDate = @OrderDate
GROUP BY ProductID
) AS Source (ProductID, OrderQty)
ON Target.ProductID = Source.ProductID
WHEN MATCHED AND Target.Quantity - Source.OrderQty <= 0
THEN DELETE
WHEN MATCHED
THEN UPDATE SET
Target.Quantity = Target.Quantity - Source.OrderQty,
Target.ModifiedDate = GETDATE()
OUTPUT $action, Inserted.ProductID, Inserted.Quantity, Inserted.ModifiedDate,
Deleted.ProductID, Deleted.Quantity, Deleted.ModifiedDate;
MERGE INTO Sales.SalesReason AS Target
USING (VALUES
('Recommendation', 'Other'),
('Review', 'Marketing'),
('Internet', 'Promotion')
) AS Source (NewName, NewReasonType)
ON Target.Name = Source.NewName
WHEN MATCHED
THEN UPDATE SET ReasonType = Source.NewReasonType
WHEN NOT MATCHED BY TARGET
THEN INSERT (Name, ReasonType) VALUES (Source.NewName, Source.NewReasonType)
OUTPUT $action, inserted.*, deleted.*;
VALUES 列建構器 (SQL 2008+) 替代 UNION ALL,簡潔高效。
CREATE TABLE Production.UpdatedInventory (
ProductID INT NOT NULL,
LocationID INT,
NewQty INT,
PreviousQty INT,
CONSTRAINT PK_UpdatedInventory PRIMARY KEY CLUSTERED (ProductID, LocationID)
)
INSERT INTO Production.UpdatedInventory (ProductID, LocationID, NewQty, PreviousQty)
SELECT ProductID, LocationID, NewQty, PreviousQty
FROM (
MERGE Production.ProductInventory AS Target
USING (
SELECT ProductID, SUM(OrderQty) AS OrderQty
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
WHERE soh.OrderDate BETWEEN '20030701' AND '20030731'
GROUP BY ProductID
) AS Source (ProductID, OrderQty)
ON Target.ProductID = Source.ProductID
WHEN MATCHED AND Target.Quantity - Source.OrderQty >= 0
THEN UPDATE SET Target.Quantity = Target.Quantity - Source.OrderQty
WHEN MATCHED AND Target.Quantity - Source.OrderQty <= 0
THEN DELETE
OUTPUT $action,
Inserted.ProductID, Inserted.LocationID, Inserted.Quantity AS NewQty,
Deleted.Quantity AS PreviousQty
) AS Changes (Action, ProductID, LocationID, NewQty, PreviousQty)
WHERE Action = 'UPDATE';
| 傳統寫法 | MERGE |
|---|---|
| 多語句:SELECT → IF EXISTS UPDATE ELSE INSERT | 單一原子性陳述式 |
| 競爭條件:檢查與更新間有間隙 | 鎖定目標表至完成,無競爭 |
| 需多次掃描來源/目標 | 單次掃描,優化器整體規劃 |
| 審計需額外邏輯 | OUTPUT 子句原生支援 |
| 刪除同步需額外邏輯 | WHEN NOT MATCHED BY SOURCE 原生支援 |
UPDATE SET Col = Source.Col WHERE Target.Col <> Source.ColMERGE ... WITH (HOLDLOCK) 序列化存取,防止幻讀TRIGGER_NESTLEVEL 判斷IS NULL 或 ISNULL() 處理INSERT ... ON DUPLICATE KEY UPDATE (MySQL)、UPSERT (PostgreSQL 9.5+)、應用層邏輯