mysql不支持单触发器处理insert和update,因语法强制要求每个触发器只能绑定一种事件类型,如before insert或before update,混写会报error 1064;必须分别创建两个触发器,并利用new/old伪记录区分操作。

不能在单个触发器里靠判断来区分 INSERT 和 UPDATE——MySQL 不支持 BEFORE INSERT, UPDATE 这种写法,语法直接报错。
为什么不能在一个触发器里处理 INSERT 和 UPDATE?
MySQL 触发器的事件类型是硬绑定的:每个触发器只能声明一种事件,比如 BEFORE INSERT 或 BEFORE UPDATE。你写 BEFORE INSERT, UPDATE 会收到错误 ERROR 1064 (42000),这不是版本差异问题,是语法层面禁止。
常见误操作是照着 SQL Server 或 Oracle 的写法抄过来,结果建不成功。
想统一记录操作类型,必须建两个独立触发器
业务上需要把 INSERT 和 UPDATE 都写进同一张日志表(比如 audit_log),就得分别定义:
-
BEFORE INSERT触发器:只访问NEW,可设operation = 'INSERT' -
BEFORE UPDATE触发器:同时读OLD和NEW,设operation = 'UPDATE',还可加条件如IF OLD.status != NEW.status THEN ...
示例片段(简化):
CREATE TRIGGER user_op_insert BEFORE INSERT ON users
FOR EACH ROW
INSERT INTO audit_log (table_name, operation, row_id, created_at)
VALUES ('users', 'INSERT', NEW.id, NOW());
CREATE TRIGGER user_op_update BEFORE UPDATE ON users
FOR EACH ROW
INSERT INTO audit_log (table_name, operation, row_id, created_at)
VALUES ('users', 'UPDATE', NEW.id, NOW());
UPDATE 触发器实际只对“值真变了”的行生效
这点容易被忽略:UPDATE users SET name='Alice' WHERE id=1 如果当前 name 就是 'Alice',该行根本不会触发任何 UPDATE 触发器——OLD 和 NEW 完全相等时,MySQL 跳过执行。
所以如果你依赖触发器做时间戳更新(比如 SET NEW.updated_at = NOW()),必须放在 BEFORE UPDATE 里,并且要确保字段确实参与了 SET;如果只想无条件更新时间戳,建议用应用层控制或生成列(MySQL 5.7+)。
别指望用 IF 判断 NEW 是否为空来识别 INSERT
有人试过在 BEFORE UPDATE 里写 IF NEW.id IS NULL THEN ... 想兼容两种操作,这不可行:UPDATE 触发器里的 NEW.id 永远非空(它来自原行),OLD.id 也一定存在。反过来,在 INSERT 触发器里访问 OLD 会直接报错 Unknown column 'OLD.id' in 'field list'。
真正的分界点只有一个:触发器定义里的事件关键字,不是运行时能绕开的逻辑分支。











