表级触发器对DDL变更无效,因其仅响应DML操作;SQL Server不支持在表上定义CREATE/ALTER/DROP监听,且EVENTDATA()在表级不可用。

能捕获,但必须用 DATABASE 级或 SERVER 级 DDL 触发器,不能用表级触发器——后者对 CREATE/ALTER/DROP 表完全无感。
为什么表级触发器对DDL变更无效
表级触发器(AFTER INSERT、INSTEAD OF UPDATE 等)只响应 DML 操作,SQL Server 明确不支持在表上定义对 CREATE TABLE 或 ALTER COLUMN 的监听。试图写 CREATE TRIGGER ... ON dbo.MyTable FOR ALTER_TABLE 会直接报错:Incorrect syntax near 'ALTER_TABLE'。
- DDL 事件属于数据库或服务器作用域,不是表对象的生命周期事件
-
EVENTDATA()在表级触发器中不可用,因为没有对应事件上下文 - 常见误操作:把 DML 审计脚本复制过来改个事件名,结果触发器根本不会被触发
DATABASE 级触发器捕获当前库的 CREATE/ALTER/DROP
适用于监控单个业务库的结构变更,比如 MyAppDB 中所有表、视图、存储过程的增删改。触发器必须建在目标库内,且权限需满足 CREATE DATABASE DDL TRIGGER(db_owner 或 sysadmin)。
- 必须用
AFTER,不能用INSTEAD OF—— 否则CREATE TABLE会被阻断,建表失败 - 事件列表要明确指定,例如:
FOR CREATE_TABLE, ALTER_TABLE, DROP_VIEW, CREATE_PROCEDURE -
EVENTDATA()返回 XML,关键字段提取方式固定:EVENTDATA().value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)')、EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname') - 日志表建议建在同库(如
dbo.DDL_Log),避免跨库写入失败导致 DDL 操作中断
SERVER 级触发器监控跨库及触发器自身变更
当你要审计 DROP TRIGGER 或 ALTER TRIGGER 这类操作时,绝不能把触发器建在目标库——否则删自己时就失效了。必须用 ON ALL SERVER,并主动过滤系统库。
- 必须加前置判断:
IF EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]', 'sysname') IN ('tempdb', 'master', 'model', 'msdb') RETURN -
CREATE OR ALTER TRIGGER会先触发DROP_TRIGGER再触发CREATE_TRIGGER,日志里是两条记录,不能靠事件类型直接合并 - 日志表必须建在不受影响的位置,推荐
master.dbo.ServerDDLLog或独立审计库(如AuditDB.dbo.DDL_History) - 无法获取“旧结构”,
EVENTDATA()只含 T-SQL 文本和元信息,不含ALTER TABLE前的列定义快照
DDL 触发器不能替代结构备份
它只记“谁在什么时候执行了什么语句”,不保存变更前的 schema 快照。想还原误删的主键或改错的字段类型,仅靠触发器日志远远不够。
-
ALTER TABLE Orders DROP CONSTRAINT PK_Orders日志里只有这一行,没有原约束定义 - 触发器不参与事务:即使你在触发器里
RAISERROR报错,ALTER TABLE已提交,无法回滚 - 真正可靠的恢复手段仍是定期导出
SELECT OBJECT_DEFINITION(object_id)或用mysqldump --no-data/pg_dump -s类工具生成 DDL 快照

















