sql server用update()判断列是否在update语句中被显式列出,不检查值是否真变;postgresql和mysql需比较old/new值并处理null,后者无is distinct from需手动判空。

SQL Server 中用 UPDATE() 函数判断列是否被修改
SQL Server 触发器里,UPDATE() 是最直接、开销最小的判断方式——它不查数据,只看语句中是否显式列出了该列。比如 UPDATE users SET name = 'Alice', email = 'a@b.com',即使 email 值没变,UPDATE('email') 仍返回 TRUE。
注意:UPDATE() 只对 UPDATE 语句有效,对 INSERT 或 DELETE 不适用;也不能用于判断值是否“实际变化”,仅反映语法层面是否被提及。
- 写法必须是
IF UPDATE(column_name),不能加表名或别名 - 多个列用多个
IF UPDATE(...)分开判断,不要合并成逻辑表达式(如UPDATE(a) AND UPDATE(b)是允许的,但嵌套太深会降低可读性) - 在
AFTER UPDATE触发器中使用,INSTEAD OF UPDATE也可用,但需注意逻辑顺序
PostgreSQL 中用 OLD 和 NEW 比较值是否真变化
PostgreSQL 没有 UPDATE() 这类语法级函数,必须靠比较 OLD.column 和 NEW.column 来判断“值是否真的变了”。这是更精确的方式,但也意味着每次都要取值、比较,尤其对大字段(如 TEXT、JSONB)可能带来额外开销。
常见错误是忽略 NULL 安全比较:直接写 OLD.col != NEW.col 在任一端为 NULL 时结果为 NULL(即 false),应改用 NOT (OLD.col IS NOT DISTINCT FROM NEW.col)。
- 对索引列或小字段,这种比较代价很低,推荐优先用
- 对大字段,可先用
OLD.col IS DISTINCT FROM NEW.col(等价于安全的不等判断)快速兜底,避免冗余计算 - 如果业务只要求“语句中出现该列”,就得在应用层或规则层提前过滤,触发器内无法低成本模拟 SQL Server 的行为
MySQL 中没有内置列变更检测,得靠 IF + 字段对比
MySQL 触发器不提供类似 UPDATE() 的函数,也不支持 IS DISTINCT FROM。唯一可行方式是显式比较 OLD.col 和 NEW.col,并手动处理 NULL。
典型写法是:IF OLD.col != NEW.col OR (OLD.col IS NULL) != (NEW.col IS NULL) THEN ... END IF;。这个条件覆盖了所有 NULL/非NULL 组合下的真实变化场景。
- 字符串比较默认区分大小写,若业务不敏感,记得用
LOWER()或对应 collation 统一处理 - 时间类型(如
DATETIME)要注意精度和时区,OLD.ts != NEW.ts可能因毫秒截断误判 - 避免在
BEFORE UPDATE中反复读取OLD/NEW,它们是只读快照,多次引用无性能问题,但逻辑混乱易出错
跨数据库通用建议:别在触发器里做复杂逻辑
无论用哪种判断方式,真正影响性能的往往不是“是否更新”的检查,而是后续动作——比如调用存储过程、写日志表、发消息。触发器本身运行在事务上下文中,任何阻塞或慢操作都会拖慢主 DML。
- 把列变更判断当作“守门人”,只用来跳过明显不需要执行的分支,别在里面做 I/O 或网络调用
- 如果需要审计“值是否真变”,且字段较大,考虑在应用层记录变更前状态,或用 CDC 工具替代触发器
- MySQL 和 PostgreSQL 中,
OLD/NEW是行级快照,不可修改;SQL Server 的inserted/deleted表也是只读,这点容易被忽略导致调试失败










