postgresql用returning直接返回修改后的行;mysql和sql server需先select for update再update,依赖事务隔离保证一致性。

UPDATE语句执行后怎么知道改了哪几行
SQL标准本身不直接返回被修改的行内容,UPDATE执行完只返回“影响行数”,但你真正想知道的是“具体哪些行变了、变成什么样了”。这事没法靠UPDATE自己解决,得靠配套手段。
用RETURNING(PostgreSQL专属)最省事
PostgreSQL支持RETURNING子句,能在更新同时把变更前/后的字段值吐出来。这是唯一能“边改边看”的原生方式。
-
UPDATE users SET status = 'active' WHERE id IN (101, 102) RETURNING id, name, status;—— 直接拿到更新后的id、name和新status - 想看旧值?得先查再更新,或者用CTE配合
OLD.*(仅限触发器或某些高级写法),RETURNING默认只返回更新后的结果 - 注意:MySQL、SQL Server、Oracle都不支持
RETURNING,写了会报错syntax error near RETURNING
MySQL / SQL Server 怎么办:先SELECT再UPDATE
没RETURNING就只能分两步:先锁定并查出待更新的行,再执行更新。关键是要保证两次操作之间数据不被并发改掉。
- 加事务 +
SELECT ... FOR UPDATE(InnoDB)或SELECT ... WITH (UPDLOCK)(SQL Server)防止其他事务干扰 - 示例(MySQL):
BEGIN; SELECT id, email, updated_at FROM users WHERE last_login
- 别漏掉
COMMIT,否则锁一直挂着;也别在事务里做耗时操作,容易锁表
临时表 or 日志表记录变更痕迹
如果要长期审计或事后追溯,靠手工SELECT+UPDATE太重,更适合建日志机制。
- 建一张
update_log表,字段含table_name、row_id、old_values(JSON)、new_values、updated_at - 用触发器(MySQL/PostgreSQL)或CDC(SQL Server Change Data Capture)自动捕获变更
- 触发器里不能直接用
NEW.*和OLD.*拼JSON?那就只存关键字段,比如UPDATE users SET balance = balance - 100 WHERE id = 123,日志里记id=123, old_balance=500, new_balance=400 - 触发器性能敏感,高频小更新场景慎用;CDC需要DBA开启,不是所有环境都支持
真正难的不是“怎么查”,而是“怎么确保查到的就是刚改的那几行”——并发、事务隔离级别、存储引擎特性都会影响结果。别只盯着SQL语法,先想清楚你的数据库用的是什么引擎、有没有权限开事务、是否允许加锁。










