MySQL触发器不支持WHERE子句,须用IF判断;SQL Server用INSERTED/DELETED表;二者均需注意条件顺序、NULL比较、批量处理及事务安全。

MySQL触发器里不能直接写 WHERE,得用 IF
MySQL 的 CREATE TRIGGER 语法不支持在定义时加 WHERE 子句筛选行(比如 FOR EACH ROW WHERE NEW.status = 'completed' 是非法的)。你必须把条件逻辑放进触发器体内部,靠 IF 判断来控制是否执行后续操作。
常见错误是直接在触发器开头写 WHERE,结果报错 ERROR 1064;或者漏掉 DELIMITER 导致语句提前截断。
- 必须用
BEGIN ... END包裹触发器逻辑,否则IF无法生效 -
OLD和NEW只在UPDATE和INSERT/DELETE中部分可用(INSERT没有OLD,DELETE没有NEW) - 多条件组合用
AND/OR,但注意 NULL 比较要用IS NULL或IS NOT NULL,别用= NULL
SQL Server 触发器用 INSERTED/DELETED 表做条件判断
SQL Server 不提供 NEW/OLD 关键字,而是通过 INSERTED 和 DELETED 这两张内存临时表来获取变更数据。条件判断必须基于这两张表做 SELECT 或 EXISTS。
典型坑点:没考虑批量操作——一次 UPDATE 可能影响多行,INSERTED 里会有 N 条记录,不能假设只有一行。
- 用
IF EXISTS (SELECT 1 FROM INSERTED WHERE salary > 100000)替代逐行处理,更高效 - 避免用游标遍历
INSERTED,除非真要对每行做差异化处理(性能差、易锁表) -
AFTER触发器中,原 DML 已提交,不能再改原表数据;要用INSTEAD OF才能拦截并重写逻辑
多条件组合时,优先级和短路逻辑要注意
MySQL 的 IF 条件表达式不支持短路求值(即 AND 左边为 false 时,右边仍会计算),而 SQL Server 的 WHERE 或 EXISTS 通常有优化器介入,实际执行可能短路。
这意味着:如果右边条件涉及函数调用或子查询,在 MySQL 里可能无谓执行,拖慢性能;在 SQL Server 里相对安全些,但也不能完全依赖。
- 把开销小、高过滤率的条件放前面(比如
NEW.status IS NOT NULL比(SELECT COUNT(*) FROM audit_log WHERE order_id = NEW.id) = 0快得多) - 避免在条件里写
SELECT子查询,尤其跨表关联,容易引发锁等待或超时 - MySQL 8.0+ 支持
WHEN子句(仅限某些存储引擎和模式),但兼容性差,生产环境慎用
触发器里做条件判断,最容易被忽略的是递归和事务边界
条件触发不是“只要写对 IF 就万事大吉”。真正上线后出问题的,往往不是语法,而是副作用。
- 触发器内再修改同一张表(比如日志表和业务表同库),可能触发另一个触发器,形成隐式递归——MySQL 默认禁用,SQL Server 需显式开
RECURSIVE_TRIGGERS - 所有触发器代码和原始 DML 在同一个事务里,一旦触发器里
INSERT失败(比如违反唯一约束),整个事务回滚,原始操作也失败 - 条件判断里别调外部服务、发 HTTP 请求、写文件——这些操作不可回滚,且严重拖慢事务
条件越细,触发器越像业务逻辑的一部分;但数据库层不该承担太多应用职责。真复杂,就该移到应用层或用队列解耦。

















