26 UPDATE
UPDATE 会修改已有行。基本形式是 UPDATE table SET column = value WHERE condition。没有 WHERE 子句时,表中的每一行都会被更新——这种错误只能在自己的练习数据库里犯。始终先用 SELECT 检查,并考虑在确认无误前将有风险的更新包在 BEGIN ... ROLLBACK 中。
本章要点
- 一次更新一列、多列和多行
- 使用
WHERE限定更新范围 - 使用
UPDATE ... FROM根据另一个表的数据更新一个表 - 使用
RETURNING返回修改后的行 UPDATE的事务安全性(以及如何滥用它)
示例
UPDATE 完全受事务保护:在你 COMMIT 之前(取决于隔离级别),其他会话看不到你的修改,而 ROLLBACK 会撤销这些修改。SELECT 的同样 WHERE 规则也适用。
UPDATE ... FROM 是 PostgreSQL 提供的扩展,允许你使用另一个表的数据更新一个表中的行。FROM 子句引入其他表,而 WHERE 子句负责将它们连接起来。这通常比在 SET 列表中嵌套关联子查询更清晰(也更快)。
psql 的状态消息 UPDATE n 会告诉你修改了多少行。UPDATE 0(零行)通常说明 WHERE 没有匹配到任何行——这对发现应用代码中的拼写错误或过时假设很有用。
运行示例
运行方式(需要前面课程创建的 fruits):
常见陷阱
- 忘记
WHERE而更新整张表——没有备份或事务时无法撤销。拿不准时,先执行BEGIN;,运行UPDATE,检查行数,再执行COMMIT;或ROLLBACK;。 - 更新被外键引用的主键:外键的
ON UPDATE动作会决定这次变更是向外传播、导致失败,还是将值设为 NULL。 - 将列更新为它已有的值,仍然会重写该行、获取锁,并触发任何
BEFORE UPDATE触发器。如果这点很重要,请添加WHERE col IS DISTINCT FROM new_value,以进行能正确处理 NULL 的比较。 - 在繁忙表上长时间运行的
UPDATE会持有行锁;并发更新会等待。将大批量更新拆分成较小的事务。
要安全地预览一次更新,可以使用公用表表达式(CTE):先运行 WITH affected AS (SELECT id FROM fruits WHERE ...) SELECT * FROM affected;。确认无误后,再把外层查询替换为 UPDATE。
把 fruits 中一行的名称改成另一个名称。使用 UPDATE fruits SET name = name || '!' WHERE id BETWEEN 1 AND 2 RETURNING *;,看看哪些行发生了变化。然后运行 BEGIN; UPDATE fruits SET name = 'X'; SELECT * FROM fruits; ROLLBACK;,确认回滚会丢弃这次修改。
下载
SQL 文件:update.sql · 全部示例文件 · 准备工作