mysql仅支持行级触发器,for each row是唯一合法语法;old和new是逐行绑定的只读伪记录,不可赋值、不可聚合,跨行统计需依赖外部表或临时表中转。

MySQL不支持语句级触发器,所以FOR EACH ROW是唯一合法语法
MySQL从5.0到8.0所有版本都不支持FOR EACH STATEMENT——这不是功能缺失,而是设计限制。你写CREATE TRIGGER ... FOR EACH STATEMENT会直接报错:ERROR 1064 (42000): You have an error in your SQL syntax。官方文档明确说明:MySQL只实现行级触发器,OLD和NEW就是为“每行一个快照”这个语义而生的。
OLD和NEW本质是逐行绑定的伪记录,不是全局变量
OLD和NEW不是变量,不能赋值、不能声明、不能传参;它们是MySQL在执行DML时为**当前正在处理的那一行**自动创建的只读结构体。INSERT影响3行,触发器就运行3次,每次NEW都指向不同的待插入行;UPDATE匹配5条记录,OLD和NEW就各对应5组不同值。如果强行想在语句级复用,根本不存在“当前行”的上下文。
试图绕过FOR EACH ROW会直接失败
- 漏写
FOR EACH ROW:触发器创建失败,报错ERROR 1363: There is no NEW row in on INSERT statement或类似提示 - 用
SELECT * FROM OLD或JOIN OLD ON ...:语法错误,OLD和NEW不能出现在FROM子句里,它们不是表名也不是别名 - 在触发器里对
OLD.id做聚合(如SUM(OLD.id)):报错或返回NULL,因为OLD只代表单行,无聚合上下文
跨行逻辑必须靠外部表或临时表中转
如果你真需要“本次UPDATE一共改了多少行”的统计信息,OLD/NEW帮不上忙。可行做法只有两种:
- 在触发器外建一张计数表,用
AFTER UPDATE往里写入ROW_COUNT()结果 - 把关键字段(如
OLD.id,NEW.status)先存进临时表,再用存储过程查这张临时表做聚合
注意:临时表在触发器里不可见,必须用普通表+唯一事务ID标记,否则并发下数据会混。











