触发器必须用 before 而不是 after,因 after 阶段 new 不可修改;需声明为 before update on table_name for each row,函数返回 new;时间戳更新可选全行或指定字段比对,default current_timestamp 仅作用于 insert。

触发器必须用 BEFORE 而不是 AFTER
如果你写成 AFTER UPDATE 触发器,再在函数里改 NEW.update_time,实际不会生效——因为 AFTER 阶段的 NEW 已不可修改,数据库会静默忽略赋值。只有 BEFORE 触发器才能拦截并修改即将插入或更新的行。
常见错误现象:UPDATE 执行后 update_time 没变,但触发器函数明明写了 NEW.update_time = now()。
- 必须声明为
BEFORE UPDATE ON table_name FOR EACH ROW - 不能漏掉
FOR EACH ROW(语句级触发器不适用此场景) - 函数返回值必须是
NEW(否则整行会被丢弃)
update_timestamp() 函数里要不要加字段变更判断?
加不加取决于业务需求。默认行为是“只要执行了 UPDATE 语句,就更新时间戳”,哪怕所有字段值都没变。但有些场景(比如日志审计)要求只在数据真实变化时才更新,这时得显式比对:
关键逻辑是这句:IF row(NEW.*) IS DISTINCT FROM row(OLD.*) THEN
- 用
IS DISTINCT FROM而不是!=,它能正确处理NULL值比较 - 如果只是想监控某几个字段(比如只关心
name和status),可改成IF NEW.name IS DISTINCT FROM OLD.name OR NEW.status IS DISTINCT FROM OLD.status - 性能上,全行比较在宽表(几十列)下有轻微开销,但通常可忽略
为什么不能只靠 DEFAULT CURRENT_TIMESTAMP?
DEFAULT 只在 INSERT 时起作用,UPDATE 完全不触发。你执行 UPDATE users SET name='foo' WHERE id=1,哪怕没提 update_time 字段,它也不会自动刷新。
name: create-psychological-counselor 心理咨询师创造器 创造/蒸馏心理咨询师的数字分身 description: "Create a psychological counselor AI skill, build digital twin of counselor from education/training background, consultation notes, interview transcripts, supervision records,
容易踩的坑:
- 误以为加了
DEFAULT CURRENT_TIMESTAMP就万事大吉,结果上线后发现更新时间始终是创建时间 - 在
UPDATE语句里显式写update_time = CURRENT_TIMESTAMP,看似可行,但一旦应用层漏写,时间就失真;触发器才是兜底方案 -
CURRENT_TIMESTAMP和now()在 PostgreSQL 中行为一致,但后者更短、更常用
触发器和函数名大小写敏感吗?
PostgreSQL 默认把未加引号的标识符转为小写。所以 CREATE FUNCTION update_timestamp() 和调用时写的 update_timestamp() 是匹配的;但如果你建函数时用了双引号:CREATE FUNCTION "UpdateTimestamp"(),那后续 CREATE TRIGGER 里也必须写成 "UpdateTimestamp"(),否则报错 function updatestimestamp() does not exist。
建议统一用小写字母+下划线命名,避免引号和大小写陷阱。
真正容易被忽略的是:触发器函数一旦部署,后续表结构变更(比如重命名字段)不会自动同步到函数体里——你得手动改函数定义并 CREATE OR REPLACE,否则下次更新就会报列不存在。










