SQL Server 2005 引入 DDL 觸發器,可在資料庫層級或伺服器層級攔截 CREATE/ALTER/DROP 等結構變更,實現防誤刪、稽核記錄、合規強制等需求,超越傳統 DML 觸發器範疇。
ON DATABASE(單一資料庫)或 ON ALL SERVER(整個實例)。CREATE_TABLE)或群組(如 DDL_DATABASE_LEVEL_EVENTS)。EVENTDATA() 回傳 XML,含事件類型、物件名稱、TSQL 指令、登入用戶、時間等完整上下文。-- 建立測試環境
CREATE DATABASE DDLTrTest;
GO
USE DDLTrTest;
GO
CREATE TABLE MyTable (ID INT, Name VARCHAR(100));
INSERT INTO MyTable VALUES (1,'A'),(2,'B');
GO
CREATE PROC usp_QueryMyTable AS SELECT * FROM MyTable;
GO
-- 定義 DDL 觸發器
CREATE TRIGGER TRG_Block_DDL_Table_Proc
ON DATABASE
FOR CREATE_TABLE, DROP_TABLE, ALTER_TABLE,
CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE
AS
BEGIN
-- 記錄嘗試指令
DECLARE @Cmd NVARCHAR(MAX) = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'NVARCHAR(MAX)');
INSERT INTO DDL_AuditLog (EventTime, LoginName, EventType, CommandText)
VALUES (GETDATE(), SYSTEM_USER, EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]', 'SYSNAME'), @Cmd);
-- 阻止並回滾
PRINT '禁止建立/修改/刪除資料表與預存程序!';
ROLLBACK;
END;
GO
ALTER TABLE MyTable ADD X INT;
-- 結果:
-- (1 row(s) affected)
-- 禁止建立/修改/刪除資料表與預存程序!
-- Msg 3609, Level 16, State 2, Line 1
-- 交易在觸發器中結束。批次已中止。
DROP TABLE MyTable;
-- 同樣被阻止並回滾
DISABLE TRIGGER TRG_Block_DDL_Table_Proc ON DATABASE;
ENABLE TRIGGER TRG_Block_DDL_Table_Proc ON DATABASE;
CREATE TRIGGER TRG_Block_Drop_DB
ON ALL SERVER
FOR DROP_DATABASE
AS
BEGIN
PRINT '禁止刪除資料庫!';
ROLLBACK;
END;
| 場景 | 事件群組 | 處理邏輯 |
|---|---|---|
| 結構變更稽核 | DDL_DATABASE_LEVEL_EVENTS | 寫入稽核表,含 EVENTDATA() 完整 XML |
| 命名規範強制 | CREATE_TABLE, CREATE_PROCEDURE | 解析物件名稱,不符規範則 ROLLBACK |
| 防止生產環境誤刪 | DROP_TABLE, DROP_PROCEDURE, DROP_VIEW | 僅允許特定角色(如 db_admin)執行 |
| 自動產生部署腳本 | 所有 CREATE/ALTER | 將 CommandText 寫入版控資料表 |
EVENTDATA() 僅在觸發器內有效,不可外傳。CONTROL SERVER 權限建立。DDL 觸發器是資料庫治理的利器,善用它將「事後追查」轉為「事前阻擋與自動留痕」。