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

SQL Server 觸發器完整指南:DML/INSTEAD OF/列級/遞迴/巢狀與實戰範例

     編輯:關於SqlServer

觸發器核心觀念

  • 特殊儲存程序,**由事件自動觸發** (非显式呼叫)
  • 依附於**資料表**或**檢視表**
  • 執行於**同一交易**內,可透過 ROLLBACK 取消觸發動作
  • 兩張虛擬資料表:**inserted** (新/修改後資料)、**deleted** (舊/刪除資料),唯讀、記憶體駐留

觸發器分類

類別觸發時機適用物件特點
AFTER (FOR)動作完成**後**Table可多個、可指定順序 (sp_settriggerorder)
INSTEAD OF**取代**原動作Table / View每表每事件僅一個、可更新不可更新 View
DDLCREATE/ALTER/DROP 等Database / ServerSQL 2005+,審計、防護結構變更

虛擬表資料對應

動作inserteddeleted
INSERT新增列空
DELETE空被刪除列
UPDATE修改後列修改前列

實戰範例集

1. AFTER INSERT:聯動新增


CREATE TRIGGER tgr_Classes_Insert ON Classes
AFTER INSERT
AS
BEGIN
    DECLARE @id INT, @name VARCHAR(20);
    SELECT @id = id, @name = name FROM inserted;
    INSERT INTO Student (Name, Age, ClassID) 
    VALUES (@name + CAST(@id AS VARCHAR), 18 + @id, @id);
    PRINT '學生聯動新增成功';
END

2. AFTER DELETE:刪除備份


CREATE TRIGGER tgr_Classes_Delete ON Classes
AFTER DELETE
AS
BEGIN
    IF OBJECT_ID('ClassesBackup', 'U') IS NOT NULL
        INSERT INTO ClassesBackup SELECT name, createDate FROM deleted;
    ELSE
        SELECT * INTO ClassesBackup FROM deleted;
    PRINT '刪除資料已備份';
END

3. AFTER UPDATE:級聯更新


CREATE TRIGGER tgr_Classes_Update ON Classes
AFTER UPDATE
AS
BEGIN
    DECLARE @oldName VARCHAR(20), @newName VARCHAR(20);
    SELECT @oldName = name FROM deleted;
    SELECT @newName = name FROM inserted;
    IF EXISTS (SELECT 1 FROM Student WHERE Name LIKE '%' + @oldName + '%')
    BEGIN
        UPDATE Student SET Name = REPLACE(Name, @oldName, @newName)
        WHERE Name LIKE '%' + @oldName + '%';
        PRINT '級聯修改完成';
    END
END

4. 列級觸發:防護特定欄位修改


CREATE TRIGGER tgr_Classes_Update_Column ON Classes
AFTER UPDATE
AS
BEGIN
    IF UPDATE(createDate)  -- 偵測 createDate 是否在 SET 子句中
    BEGIN
        RAISERROR('建立日期不可修改', 16, 1);
        ROLLBACK TRANSACTION;
    END
END

5. INSTEAD OF DELETE:級聯刪除 (含子表)


CREATE TRIGGER tgr_Classes_InsteadOf_Delete ON Classes
INSTEAD OF DELETE
AS
BEGIN
    DECLARE @id INT, @name VARCHAR(20);
    SELECT @id = id, @name = name FROM deleted;
    DELETE FROM Student WHERE ClassID = @id;  -- 先刪子表
    DELETE FROM Classes WHERE id = @id;       -- 再刪主表
    PRINT '主從表級聯刪除完成';
END

6. 多事件合一 + 自訂訊息


CREATE TRIGGER tgr_Student_Log ON Student
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
    DECLARE @action VARCHAR(10);
    IF EXISTS (SELECT 1 FROM inserted) AND EXISTS (SELECT 1 FROM deleted)
        SET @action = 'UPDATED';
    ELSE IF EXISTS (SELECT 1 FROM inserted)
        SET @action = 'INSERTED';
    ELSE
        SET @action = 'DELETED';
    INSERT INTO LogTable (Action, LogTime) VALUES (@action, GETDATE());
END

7. 資料驗證 + 回滾


CREATE TRIGGER tgr_Student_ValidAge ON Student
AFTER INSERT
AS
BEGIN
    DECLARE @age INT;
    SELECT @age = Age FROM inserted;
    IF @age < 18
    BEGIN
        RAISERROR('年齡必須 >= 18', 16, 1);
        ROLLBACK TRANSACTION;
    END
END

管理與維護

操作T-SQL
停用DISABLE TRIGGER tgr_Name ON TableName;
啟用ENABLE TRIGGER tgr_Name ON TableName;
修改ALTER TRIGGER ...
查看定義EXEC sp_helptext 'tgr_Name';
列出所有SELECT * FROM sys.triggers;
查看觸發事件SELECT * FROM sys.trigger_events te JOIN sys.triggers t ON t.object_id = te.object_id WHERE t.name = 'tgr_Name';

效能與最佳實踐

  1. **避免複雜邏輯**:觸發器在交易內執行,長耗時會阻塞並發
  2. **集合式思維**:勿假設 inserted/deleted 只有一列,使用 JOIN/EXISTS 處理多列
  3. **謹慎使用巢狀/遞迴**:sp_configure 'nested triggers', 0 可關閉
  4. **INSTEAD OF 更新 View** 是解決不可更新 View 的標準模式
  5. **審計/日誌** 場景首選觸發器;**跨表業務邏輯** 建議移至儲存程序/服務層

觸發器是資料庫完整性與審計的最後一道防線,善用其事件驅動特性,配合集合式操作,能優雅解決許多跨表一致性需求。

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