delete触发器中new完全禁止使用,引用即报error 1363,因delete不产生新行;old是唯一可用且只读的被删行快照,适用于归档或条件校验。

DELETE触发器里访问NEW会直接报错ERROR 1363
因为NEW语义上代表“即将插入或更新后的新行”,而DELETE操作不产生任何新行——它只移除已有数据。MySQL在语法解析阶段就禁止这种用法,不是运行时才检查。一旦触发器里出现NEW.id、NEW.status这类引用,哪怕只是SELECT NEW.id或IF NEW.id IS NOT NULL,都会立刻中断创建或执行,抛出ERROR 1363 (HY000): There is no NEW row in on DELETE trigger。
OLD是DELETE触发器中唯一可用的行级引用
OLD指向被删除的那一行的完整快照,字段名、类型、NULL性都与原表一致。它只读,不能赋值(如SET OLD.status = 'deleted'会报错),但可安全用于:
- 归档:例如
INSERT INTO archive_table SELECT OLD.* - 条件校验:比如
IF OLD.balance - 关联清理:如
DELETE FROM order_items WHERE order_id = OLD.id
OLD在BEFORE DELETE和AFTER DELETE中都有效,但BEFORE更适合做拦截,AFTER更适合做归档。
常见误写:混用INSERT/UPDATE逻辑到DELETE触发器
很多开发者把INSERT或UPDATE触发器的模板直接复制到DELETE里,结果栽在NEW上。典型错误包括:
- 在
AFTER DELETE里写INSERT INTO log VALUES (NEW.id, 'deleted')——NEW根本不存在 - 用
IF NEW.deleted_at IS NULL THEN ...做软删判断,却忘了这是DELETE物理删除,不是UPDATE - 试图用
NEW字段参与子查询:SELECT name FROM users WHERE id = NEW.ref_id,同样触发ERROR 1363
OLD,没有NEW,连读都不行”。
别指望用NEW绕过限制,MySQL不给任何商量余地
有人试过在DELETE触发器里声明局部变量再赋值NEW字段,或者用PRECEDES/FOLLOWS指定触发器顺序,甚至升级到MySQL 8.4——全无效。NEW在DELETE上下文中就是语法级非法,不是版本缺陷,也不是配置问题。如果你真需要“删除时基于新状态做点什么”,说明设计已偏离触发器本意:要么把逻辑移到应用层(比如先查再删再处理),要么用AFTER DELETE往日志表写OLD数据,由后台任务异步消费。最常被忽略的一点是:触发器里的OLD字段值,是事务开始时那一行的快照,如果并发中该行刚被UPDATE过,你拿到的就是最新值;但它不会帮你锁住这行,也不会自动重试——这些都得你自己兜底。











