在INSERT触发器中,新增记录字段值必须通过NEW关键字访问,如NEW.id、NEW.email;BEFORE中可读写,AFTER中只读且修改无效;不同数据库语法不同:MySQL用NEW.字段名,SQL Server用FROM INSERTED,Oracle用:NEW.字段名。

触发器里怎么拿到新插入的那条数据
在 INSERT 触发器中,新增记录的字段值通过 NEW 关键字访问,它是一个虚拟行对象(不是真实表),代表即将插入或刚插入的那条记录。不同数据库语法略有差异,但核心逻辑一致:你不能用 SELECT * FROM 表名 WHERE ... 去查——因为这条记录可能还没落盘(尤其在 BEFORE INSERT 中),必须直接读 NEW。
-
NEW.字段名是唯一可靠方式,比如NEW.id、NEW.email - 在
BEFORE INSERT中可读可写:SET NEW.created_at = NOW(); - 在
AFTER INSERT中只读,修改NEW无效(MySQL 报错,PostgreSQL 忽略) - Oracle 使用
:NEW.字段名(带冒号),SQL Server 用INSERTED.字段名(需配合FROM INSERTED)
MySQL 触发器中读取新增字段的典型写法
以 MySQL 为例,假设有一张 users 表,想在插入时自动记录日志:
DELIMITER $$
CREATE TRIGGER log_user_insert
AFTER INSERT ON users
FOR EACH ROW
BEGIN
INSERT INTO user_log(action, email, created_at)
VALUES('INSERT', NEW.email, NEW.created_at);
END$$
DELIMITER ;注意点:
-
NEW.email直接取值,无需加引号或反引号(除非字段名含特殊字符) - 如果
email允许为NULL,NEW.email就是NULL,不用额外判空(但业务逻辑里该判还得判) - 别在触发器里调用耗时函数(如远程 API、大表 JOIN),容易拖慢主 SQL 执行
PostgreSQL 和 SQL Server 的关键区别
PostgreSQL 和 SQL Server 不支持 NEW 这种简写,必须显式从虚拟表中查:
- PostgreSQL:用
NEW.字段名(和 MySQL 类似),但在AFTER触发器中仍可用;若要多行操作,得配合FOR EACH STATEMENT+OLD TABLE/NEW TABLE - SQL Server:必须用
INSERTED表,且只能在FROM INSERTED子句中引用,例如:SELECT email FROM INSERTED;不支持INSERTED.email这种点号访问 - SQL Server 中如果触发器处理批量插入(如
INSERT INTO t SELECT ...),INSERTED可能含多行,必须用集合操作,不能假设单行
最容易被忽略的坑:NULL 值和默认值冲突
当字段定义了 DEFAULT 或允许 NULL,而插入语句没指定值时,NEW.字段名 的行为取决于触发器时机:
-
BEFORE INSERT中,NEW.字段名是 SQL 语句传入的原始值(未填充默认值),哪怕字段定义了DEFAULT CURRENT_TIMESTAMP,此时NEW.created_at仍是NULL -
AFTER INSERT中,NEW.字段名是最终写入表的值(已应用默认值、自增、触发器修改等) - 所以,如果想在
BEFORE中补默认时间,必须显式赋值:SET NEW.created_at = NOW();,不能依赖表定义
跨数据库移植触发器时,这个细节常导致逻辑偏差——尤其是默认值由数据库引擎填充,而非客户端传入。

















