SQL Server 2005 引入 OUTPUT 子句,打破傳統 DML (INSERT/UPDATE/DELETE) 僅回傳影響筆數的限制,允許在單一陳述式中將異動前後的資料影像直接導向資料表變數、暫存表或呼叫端應用程式。這為稽核追蹤、異步處理、資料封存、ETL 增量邏輯帶來革命性簡化。
INSERT | UPDATE | DELETE ...
OUTPUT INTO @table_variable | #temp_table
...
| 虛擬表 | 含義 | 適用 DML |
|---|---|---|
| inserted | 新資料影像 (異動後) | INSERT, UPDATE |
| deleted | 舊資料影像 (異動前) | UPDATE, DELETE |
INSERT:僅能存取 inserted。DELETE:僅能存取 deleted。UPDATE:可同時存取 inserted (新值) 與 deleted (舊值),極適合稽核欄位級異動。情境: Orders 表達 TB 級,需定期將 2003 年前訂單移至 OrdersArchive,要求交易一致性、最小化鎖爭用、可中斷續傳。
DECLARE @deletedOrders TABLE (
orderid INT,
orderdate DATETIME,
empid INT,
custid VARCHAR(5),
qty INT
);
WHILE 1 = 1
BEGIN
BEGIN TRAN;
-- 1. 批次刪除 5000 筆,並用 OUTPUT 將被刪列導向表變數
DELETE TOP (5000) FROM Orders
OUTPUT deleted.* INTO @deletedOrders
WHERE orderdate < '20030101';
-- 2. 將批次資料寫入封存表
INSERT INTO OrdersArchive
SELECT * FROM @deletedOrders;
COMMIT TRAN;
-- 3. 清空表變數供下一批次
DELETE FROM @deletedOrders;
-- 4. 終止條件:實際刪除筆數 < 批次大小,表示已處理完畢
IF @@ROWCOUNT < 5000
BREAK;
END
@deletedOrders 僅存在記憶體 (或 TempDB 溢寫),批次間清空釋放,無持久化開銷。UPDATE dbo.Products
SET Price = Price * 1.1
OUTPUT inserted.ProductID, deleted.Price AS OldPrice, inserted.Price AS NewPrice, GETDATE() AS ChangeTime
INTO dbo.PriceAudit
WHERE CategoryID = 5;
DECLARE @NewOrders TABLE (OrderID INT, OrderDate DATETIME, Total MONEY);
INSERT INTO Orders (CustomerID, OrderDate, Total)
OUTPUT inserted.OrderID, inserted.OrderDate, inserted.Total INTO @NewOrders
VALUES ('ALFKI', GETDATE(), 123.45);
-- @NewOrders 即包含完整新列,含 Identity、Default、Computed 欄位
MERGE INTO Target t
USING Source s ON t.Key = s.Key
WHEN MATCHED THEN UPDATE SET t.Val = s.Val
WHEN NOT MATCHED THEN INSERT (Key, Val) VALUES (s.Key, s.Val)
OUTPUT $action, inserted.*, deleted.* INTO @MergeAudit;
-- $action 回傳 'INSERT' / 'UPDATE' / 'DELETE'
#temp_table + 索引。OUTPUT 子句是 T-SQL 邁向「資料流程式設計」的關鍵一步,將 DML 從「黑盒執行」轉為「可觀測、可組合」的資料管線元件。掌握其模式,能以極簡代碼實現企業級資料異動追蹤、封存遷移、即時同步等核心能力。