mysql用old.column_name、postgresql用old.column_name(需函数参数)、sql server用deleted表,均须通过触发器上下文获取旧值而非查表,且null比较需用is distinct from等安全方式。

触发器里怎么拿到 UPDATE 前的旧值
在 MySQL、PostgreSQL 或 SQL Server 中,BEFORE UPDATE 触发器天然支持访问旧值——但具体用什么变量、语法是否一致,得看数据库类型。核心原则是:别直接查原表,要用触发器上下文提供的伪记录(如 OLD 或 DELETED),否则可能读到刚被修改但尚未提交的数据,甚至引发死锁。
MySQL 的 OLD 和 NEW 怎么用
MySQL 触发器中,OLD 指更新前的行,NEW 是更新后的行。必须用 BEFORE UPDATE 才能安全读取 OLD;AFTER UPDATE 里 OLD 仍可用,但此时原表已变更,若再查表可能不一致。
-
OLD.column_name直接引用某列旧值,比如想捕获email列被改前的内容,就写OLD.email - 不能对
OLD赋值,它只读;但可以给NEW.column_name赋值来覆盖即将写入的值 - 如果只关心特定列是否被更新,用
IF OLD.email != NEW.email THEN ...判断,注意 NULL 比较要用IS DISTINCT FROM(MySQL 8.0.22+)或手动处理 NULL
CREATE TRIGGER log_email_change
BEFORE UPDATE ON users
FOR EACH ROW
BEGIN
IF OLD.email != NEW.email THEN
INSERT INTO user_audit (user_id, old_email, new_email, changed_at)
VALUES (OLD.id, OLD.email, NEW.email, NOW());
END IF;
END;
PostgreSQL 的 OLD 和 NEW 有啥不同
和 MySQL 类似,但 PostgreSQL 触发器函数是独立的,OLD 和 NEW 是函数参数传入的记录类型,且必须显式声明返回类型(如 TRIGGER)。关键差异在于 NULL 安全比较更严格。
- 用
OLD.email IS DISTINCT FROM NEW.email替代!=,它天然处理两边为 NULL 的情况 - 触发器函数体里不能直接用
OLD.email,得先声明变量接收,或在INSERT语句中直接引用 - 如果触发器定义为
FOR EACH ROW,每行更新都触发一次,OLD始终对应当前行原始值
CREATE OR REPLACE FUNCTION log_price_change()
RETURNS TRIGGER AS $$
BEGIN
IF OLD.price IS DISTINCT FROM NEW.price THEN
INSERT INTO price_audit VALUES (OLD.id, OLD.price, NEW.price, now());
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
SQL Server 里没有 OLD,怎么取更新前值
SQL Server 不提供 OLD 关键字,而是通过 deleted 临时表访问更新前数据。它只在 UPDATE 和 DELETE 触发器中存在,本质是包含所有被影响行旧值的结果集。
-
deleted是表名,不是变量,必须用FROM deleted或JOIN方式访问,不能写deleted.price单独引用 - 因为是结果集,多行更新时
deleted可能含多行,需用JOIN inserted ON deleted.id = inserted.id对齐新旧行 - 不要在触发器里再对原表做
SELECT,尤其是带条件的,容易造成阻塞或读到中间状态
CREATE TRIGGER tr_capture_salary_change ON employees AFTER UPDATE AS BEGIN INSERT INTO salary_audit (emp_id, old_salary, new_salary, updated_at) SELECT d.id, d.salary, i.salary, GETDATE() FROM deleted d INNER JOIN inserted i ON d.id = i.id WHERE d.salary != i.salary; END;
真正难的不是语法,是意识到:触发器里的“旧值”必须来自触发器上下文本身,而不是重新查表。跨事务、高并发下,查表拿到的很可能不是你要的“那一刻”的值。另外,所有数据库里,NULL 比较都是坑,别信 != 能搞定一切。










