首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 觸發器實戰全解:INSERTED/DELETED 虛擬表、DML/DDL/INSTEAD OF 觸發器與視圖應用

     編輯:關於SqlServer

觸發器基礎範例:同步工程名稱

CREATE TRIGGER TG_ProjectName
ON Table1
AFTER UPDATE
AS
BEGIN
    UPDATE Table2
    SET [工程名] = i.工程名
    FROM Table2 t
    INNER JOIN inserted i ON t.ProjID = i.ID;
END

核心概念:INSERTED 與 DELETED 虛擬表

特性:記憶體駐留、唯讀、觸發器範圍內可用、不可直接修改資料。

觸發器分類與適用場景

操作INSERTEDDELETED說明
INSERT新列 (完整)空新資料同時寫入表與 INSERTED
DELETE空舊列 (完整)舊資料從表移至 DELETED
UPDATE新列 (更新後)舊列 (更新前)相當於 DELETE + INSERT
類型觸發時機典型用途INSERTED/DELETED 可用性
AFTER (FOR)動作完成、約束檢查後稽核日誌、跨表同步、衍生資料維護、郵件通知完整可用
INSTEAD OF**取代** 原動作執行視圖更新、複雜業務規則攔截、跨表原子操作、軟刪除實作完整可用
DDLCREATE/ALTER/DROP/DISABLE/ENABLE結構變更稽核、防止誤刪、自動同步結構**不可用** (使用 EVENTDATA())

AFTER 觸發器進階規則

  1. 多列更新檢測:`IF UPDATE(欄位名)` 或 `COLUMNS_UPDATED()` 位元遮罩判斷特定欄位是否被修改。
  2. 多列觸發處理:觸發器**一次處理整批列**,不可假設單列。需用 `INSERTED`/`DELETED` 集合操作 (JOIN/EXISTS),而非標量變數。
  3. 遞迴/巢狀觸發:預設允許 (巢狀 32 層)。`sp_configure 'nested triggers', 0` 關閉。遞迴觸發需 `RECURSIVE_TRIGGERS` 資料庫選項開啟。
  4. TEXT/NTEXT/IMAGE 限制:SQL 2000 AFTER 觸發器不可引用這三類大物件欄位;INSTEAD OF 可引用。SQL 2005+ 已移除此限制 (型別改為 MAX)。

INSTEAD OF 觸發器:視圖更新的關鍵

視圖含衍生欄位、多表 JOIN、聚合時**不可直接更新**。INSTEAD OF 觸發器接管更新邏輯:

CREATE VIEW EmployeeNames (EmployeeID, LName, FName)
AS SELECT EmployeeID, LastName, FirstName FROM Employees;

CREATE TRIGGER TR_EmployeeNames_Update
ON EmployeeNames
INSTEAD OF UPDATE
AS
BEGIN
    UPDATE Employees
    SET LastName = i.LName, FirstName = i.FName
    FROM Employees e
    INNER JOIN inserted i ON e.EmployeeID = i.EmployeeID;
END

INSERTED/DELETED 結構** 與視圖 SELECT 清單一致,而非基表結構。衍生運算式 (常數、函數) 會被忽略,複雜運算式需觸發器自行處理。

DDL 觸發器:伺服器/資料庫級結構稽核

-- 資料庫級:防止誤刪表
CREATE TRIGGER TR_Prevent_Drop_Table
ON DATABASE
FOR DROP_TABLE
AS
BEGIN
    PRINT '資料庫禁止直接 DROP TABLE,請使用受控部署流程。';
    ROLLBACK;
    -- 可用 EVENTDATA() 取得登入名、物件名、SQL 文本、時間
END

-- 伺服器級:稽核所有 CREATE_LOGIN
CREATE TRIGGER TR_Audit_Create_Login
ON ALL SERVER
FOR CREATE_LOGIN
AS
BEGIN
    INSERT INTO AuditDB.dbo.LoginAudit (EventXML, EventTime)
    VALUES (EVENTDATA(), GETDATE());
END

實戰避坑清單

  1. 效能殺手:觸發器內跨資料庫/Linked Server 呼叫、發送郵件、複雜計算 → 改為非同步 (Service Broker/訊息佇列/排程作業)。
  2. 遞迴死循環:觸發器更新同表 → 再次觸發 → 無限循環。對策:`IF TRIGGER_NESTLEVEL() > 1 RETURN;` 或關閉遞迴觸發選項。
  3. 交易範圍:觸發器執行於**觸發動作的同一交易**中。觸發器 `ROLLBACK` 會回滾原動作。長時間觸發器 = 長交易 = 鎖升級/阻塞風險。
  4. 權限:觸發器以**建立者權限**執行 (擁有權鏈)。若觸發器存取其他資料庫/伺服器物件,需確保建立者有權限。
  5. 除錯:SSMS 無法直接中斷點觸發器。改用 `PRINT`/`RAISERROR(... WITH NOWAIT)` 輸出訊息至「訊息」頁籤,或寫入稽核表。

小結

觸發器是資料庫端業務邏輯的「最後一道防線」與「自動化執行器」。掌握 `INSERTED`/`DELETED` 語義、AFTER vs INSTEAD OF 選型、DDL 觸發器稽核範圍、視圖更新代理、效能與交易陷阱,**善用觸發器簡化應用層、濫用觸發器拖垮資料庫**。原則:**能用約束/預設值/計算欄位解決的,絕不寫觸發器;必須寫時,儘量簡單、集合化、非同步化**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved