mysql通过old/new存在性判断事件类型:insert中仅new可用,update中两者均可用;postgresql用tg_op变量直接获取操作类型;sql server依赖inserted/deleted表组合判断。

MySQL里看 NEW 和 OLD 是否存在
MySQL触发器本身不提供运行时“判断类型”的函数,但你可以靠 OLD 和 NEW 两个伪记录的存在性来反推事件类型。这是最直接、最可靠的方式,不需要额外变量或状态。
常见错误现象:有人试图在同一个触发器里写 IF ... THEN ... ELSE 来区分 INSERT/UPDATE,却建成了 AFTER INSERT 触发器——这种写法根本不会进 UPDATE 分支,因为 UPDATE 语句压根不会激活它。
-
INSERT触发器中:NEW可用,OLD不可用(会报错Unknown column 'OLD.id' in 'field list') -
UPDATE触发器中:OLD和NEW都可用 - 所以,如果你必须在一个触发器里处理多种操作(比如用
BEFORE INSERT OR UPDATE—— MySQL 8.0.19+ 支持),就只能靠OLD是否为NULL判断:若OLD.id IS NULL,大概率是 INSERT;否则是 UPDATE
PostgreSQL里读 TG_OP 变量
PostgreSQL 提供了内置变量 TG_OP,它的值就是字符串 'INSERT'、'UPDATE' 或 'DELETE',直接拿来判断就行。这是 PostgreSQL 原生支持的、最干净的方式。
使用场景:审计日志表需要统一入口,但 INSERT 和 UPDATE 要写不同字段(比如 INSERT 记 created_at,UPDATE 记 updated_at)。
IF TG_OP = 'INSERT' THEN ... END IF;IF TG_OP = 'UPDATE' THEN ... END IF;- 注意:
TG_OP是大小写敏感的,必须全大写 - 这个变量只在触发器函数体内有效,不能在外部 SQL 中引用
SQL Server里查 inserted 和 deleted 表
SQL Server 没有 NEW/OLD,而是用两个逻辑表:inserted 和 deleted。它们的组合就是判断依据。
容易踩的坑:有人误以为 inserted 表非空就一定是 INSERT,但 UPDATE 也会填充 inserted(新值)和 deleted(旧值)——漏判 deleted 就会导致 UPDATE 被当成 INSERT。
- 只有
inserted有数据、deleted为空 → INSERT -
inserted和deleted都有数据 → UPDATE - 只有
deleted有数据、inserted为空 → DELETE - 判断方式通常是
IF EXISTS(SELECT 1 FROM inserted) AND NOT EXISTS(SELECT 1 FROM deleted)
为什么不能依赖 SQL 语句文本或客户端传参
触发器响应的是实际执行的 DML 行为,不是 SQL 字符串内容。哪怕你写 UPDATE t SET x = x,如果 x 值没变,MySQL 的 UPDATE 触发器根本不会触发;反过来,REPLACE INTO 看似像 UPDATE,实际走的是 INSERT 触发器路径。
性能影响:在触发器里做跨表查询或复杂条件判断(比如查配置表决定是否记录日志)会拖慢主 DML 执行,尤其高并发写入时。更稳的做法是把判断逻辑前置到应用层,或拆成多个专用触发器。
真正容易被忽略的是 TRUNCATE —— 它不走任何触发器,也不产生 inserted/deleted 表,更不会设置 TG_OP。如果业务依赖删除日志,却用了 TRUNCATE 清表,监控和审计就彻底断档。










