觸發器 是附著在資料表/檢視上的特殊預存程序,當 INSERT、UPDATE、DELETE 發生時**自動執行**。分類:
部門 A 維護酒店基礎資料 (含價格)。部門 B 需同步建立「積分酒店」,價格 = 基礎價格 × 100。
方案對比:
| 方案 | 優點 | 缺點 |
|---|---|---|
| 修改部門 A 寫入程式 | 邏輯集中、即時 | 跨部門協調難、程式碼耦合、維護風險高 |
| AFTER INSERT 觸發器 | 零侵入、部署獨立、邏輯封裝在 DB 層 | 隱性邏輯、除錯較難、效能影響需評估 |
| 虛擬表 | 內容 | 適用事件 |
|---|---|---|
inserted | 新增的列 / 更新後的新值 | INSERT, UPDATE |
deleted | 刪除的列 / 更新前的舊值 | DELETE, UPDATE |
**無 updated 表**;UPDATE 內部實作為 DELETE + INSERT。
若 INSERT 因約束違規失敗,觸發器**完全不會執行**。保證觸發器內邏輯只處理已持久化資料。
UPDATE Table SET Col=1 WHERE 1=0 (影響 0 列) 仍會觸發。
**最佳實踐**:觸發器第一行就判斷 @@ROWCOUNT。
CREATE TRIGGER trg_Example ON dbo.TargetTable
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
IF @@ROWCOUNT = 0 RETURN; -- 關鍵:零列即刻退出,節省資源、避免鎖定擴大
-- 正常業務邏輯...
END;
觸發器內的 SELECT、PRINT 會向呼叫端 (ADO.NET、ODBC 等) 送出**額外結果集**,導致:
**除錯時用** RAISERROR('Debug', 0, 1) WITH NOWAIT **寫入錯誤記錄檔**,上線前移除。
| 操作 | T-SQL 指令 |
|---|---|
| 查看資料表關聯觸發器 | EXEC sp_helptrigger 'TableName'; |
| 查看觸發器定義 | EXEC sp_helptext 'TriggerName'; |
| 刪除觸發器 | DROP TRIGGER TriggerName; |
| 修改觸發器 | ALTER TRIGGER TriggerName ... |
| 重新命名 | EXEC sp_rename 'OldName', 'NewName', 'TRIGGER'; |
觸發器**不另開交易**,它在觸發它的那個交易內執行。
若觸發器發現錯誤需回滾:
IF @@ERROR <> 0 OR @BusinessRuleViolated = 1
BEGIN
ROLLBACK TRANSACTION; -- 回滾整個外部交易 (含觸發動作)
RETURN;
END
**注意**:ROLLBACK 會結束整個批次,後續程式碼不再執行。
同一資料表同一事件可有多個 AFTER 觸發器。用 sp_settriggerorder 定義 First / Last / None。
EXEC sp_settriggerorder
@triggername = 'trg_AuditLog', -- 觸發器名
@order = 'First', -- First / Last / None
@stmttype = 'INSERT'; -- INSERT / UPDATE / DELETE
CREATE TRIGGER trg_PointsHotel_PriceInit
ON dbo.PointsHotels
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
IF @@ROWCOUNT = 0 RETURN;
UPDATE ph
SET ph.Price = b.Price * 100,
ph.LastSync = SYSDATETIME()
FROM dbo.PointsHotels ph
INNER JOIN inserted i ON ph.HotelID = i.HotelID
INNER JOIN dbo.BaseHotels b ON b.HotelCode = ph.HotelCode
WHERE ph.Price IS NULL OR ph.Price = 0; -- 僅初始化未設價列
END;
AFTER 觸發器是 **「資料庫層事件處理器」**。善用它能解決跨系統、無法改代碼的同步難題;濫用它會製造「隱性邏輯地獄」。牢記:**零列早退、禁用結果集、交易共享、順序顯式設定、能用約束/SP 就不用觸發器**。