SQL Server 2005 引入 OUTPUT 子句,讓 DML 陳述式在修改資料的同時,將「修改前/後」的資料行直接回傳給用戶端或存入資料表/表變數。這對稽核追蹤、同步邏輯、應用層即時回饋極具價值。本文以實戰範例詳細解析三大 DML 的 OUTPUT 用法。
OUTPUT [ INTO { @table_variable | output_table } ]
[ WHERE ... ];
INSERTED:新資料列(INSERT/UPDATE 後)DELETED:舊資料列(UPDATE/DELETE 前)INTO 目標必須為**資料表或表變數**,不可為純標量變數。
INSERT INTO book (bkno, bkname, author, publisher, pubdate, isbn, price, remark)
OUTPUT INSERTED.*
VALUES (106, N'數字圖像處理', N'宋青書', N'科學出版社', '2006/7/1', '200607100', 25.00, N'較差');
回傳包含身分識別欄位、計算欄位、預設值等完整新列。
DECLARE @NewBooks TABLE (bkno INT, bkname NVARCHAR(50), author NVARCHAR(8));
INSERT INTO book (bkno, bkname, author, publisher, pubdate, isbn, price, remark)
OUTPUT INSERTED.bkno, INSERTED.bkname, INSERTED.author INTO @NewBooks
SELECT 104, N'JSP網站開發教程', N'趙敏', N'電子工業出版社', '2002/10/11', '200210201', 35.00, N'較好'
UNION ALL
SELECT 105, N'C++Builder程序設計', N'俞蓮舟', N'人民郵電出版社', '2007/1/1', '200701111', 53.00, N'一般';
SELECT * FROM @NewBooks; -- 後續可用於寄信、記錄稽核等
DELETE FROM book
OUTPUT DELETED.*
WHERE bkno = 104;
DECLARE @PriceChange TABLE (
preprice NUMERIC(10,2),
posprice NUMERIC(10,2),
bkno INT,
changedate DATETIME DEFAULT GETDATE()
);
UPDATE book
SET price = price * 1.3
OUTPUT DELETED.price AS preprice,
INSERTED.price AS posprice,
INSERTED.bkno
INTO @PriceChange;
SELECT * FROM @PriceChange;
典型應用:價格異動記錄、庫存變動追蹤、欄位級稽核。
| 主題 | 說明 |
|---|---|
| 觸發器 vs OUTPUT | OUTPUT 效能優於 AFTER TRIGGER,且可直接回傳用戶端;觸發器適合跨表複雜邏輯、強制業務規則。 |
| 身分識別/計算欄位 | OUTPUT 可取得 INSERT 後的身分識別值、計算欄位值,免去 SCOPE_IDENTITY() 額外查詢。 |
| MERGE 陳述式 | MERGE ... WHEN MATCHED THEN UPDATE ... WHEN NOT MATCHED THEN INSERT ... OUTPUT $action, INSERTED.*, DELETED.* 可一次捕獲增/刪/改動作。 |
| 大型物件 (LOB) | OUTPUT 不支援 text/ntext/image 與 varchar(max)/varbinary(max) 直接輸出,需用 .WRITE() 或讀取 INSERTED/DELETED 後再處理。 |
| 分區表 | UPDATE 導致資料跨分區移動時,OUTPUT 仍正確反映 INSERTED/DELETED 值。 |
| 並行處理 | OUTPUT 结果顺序与执行计划顺序一致,不保证与输入顺序相同;需含唯一鍵以便對應。 |
UPDATE testbook
SET price = price * 0.7,
remark = N'折扣促銷'
WHERE pubdate <= '2000-01-01';
UPDATE file_table
SET FileName = 'Img100.jpg',
DOCUMENT = (SELECT * FROM OPENROWSET(BULK 'C:\Img100.jpg', SINGLE_BLOB) AS Doc)
WHERE FileType = '.jpg';
| 特性 | DELETE | TRUNCATE TABLE |
|---|---|---|
| 可用 OUTPUT | ✅ | ❌ |
| 觸發器 | 啟動 AFTER DELETE | 不啟動 |
| 記錄寫入 | 逐列記錄 | 僅記錄頁面釋放 |
| 身分識別種子 | 保留 | 重置 |
| 可回滾 | ✅ | ✅ (在交易中) |
| 速度 | 較慢 | 極快 |
需要稽核軌跡時**必須用 DELETE + OUTPUT**;單純清空大表用 TRUNCATE。
SELECT
c.name AS 欄位名,
t.name AS 型別,
c.max_length AS 長度
FROM sys.all_columns c
JOIN sys.types t ON c.system_type_id = t.system_type_id
WHERE c.object_id = OBJECT_ID('dbo.student');