ALTER TRIGGER [dbo].[update_email_template]
ON [dbo].[E3_DICT_TABLE]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- 1. 判斷關注欄位是否被更新
IF (UPDATE(value))
BEGIN
-- 2. 從 deleted/inserted 取得變更前後值
-- 注意:觸發器為批次觸發,deleted/inserted 可能多列
-- 此處示範單列處理,實務需用 JOIN/EXISTS 處理多列
DECLARE @id VARCHAR(MAX), @oldValue VARCHAR(MAX), @newValue VARCHAR(MAX);
SELECT @id = id, @oldValue = value FROM deleted;
SELECT @newValue = value FROM inserted WHERE id = @id;
-- 3. 業務邏輯處理
IF (@id = '1')
BEGIN
PRINT 'ID=1 舊值: ' + @oldValue;
PRINT 'ID=1 新值: ' + @newValue;
-- 實際應用:寫入稽核表、發送通知、同步快取等
END
IF (@id = '2')
BEGIN
-- 其他邏輯
END
END
END;
| 主題 | 說明 |
|---|---|
| 多列處理 | deleted/inserted 為虛擬表,可能包含多列。切勿直接賦值給標量變數。正確做法:SELECT i.id, i.value AS new_val, d.value AS old_val FROM inserted i JOIN deleted d ON i.id = d.id; |
| UPDATE() 函數 | 僅判斷欄位「出現在 SET 子句中」,不代表值真正改變。需比對 `inserted` 與 `deleted` 確認實際變更。 |
| 遞迴觸發 | 觸發器內再次更新同表會再次觸發。預設關閉 (`RECURSIVE_TRIGGERS OFF`),若開啟需加防呆邏輯 (如 `TRIGGER_NESTLEVEL()` 或上下文資訊)。 |
| 效能考量 | 觸發器在隱含交易中執行,耗時操作 (郵件、HTTP 呼叫、跨資料庫) 會鎖定資源、拉長交易。建議: ① 寫入稽核/佇列表 → 由非同步背景作業處理。 ② 使用 `sp_send_dbmail` (非同步) 而非 `xp_sendmail`。 ③ 避免 `CURSOR`/`WHILE` 逐列處理,改用集合式操作。 |
| INSTEAD OF 觸發器 | 適用於視圖或需攔截/重寫 DML 邏輯 (如軟刪除、跨表同步)。 |
CREATE TRIGGER trg_E3_DICT_TABLE_Audit
ON dbo.E3_DICT_TABLE
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF NOT UPDATE(value) RETURN; -- 快速退出
INSERT INTO dbo.E3_DICT_TABLE_Audit (id, old_value, new_value, changed_by, changed_at)
SELECT
i.id,
d.value,
i.value,
SUSER_SNAME(), -- 或 ORIGINAL_LOGIN()
SYSDATETIME()
FROM inserted i
JOIN deleted d ON i.id = d.id
WHERE ISNULL(i.value, '') <> ISNULL(d.value, ''); -- 僅記錄真正變更
END;