PostgreSQL中跨表更新必须用UPDATE...FROM语法,目标表不可出现在FROM中,WHERE需含主键等明确关联条件以避免误更新。

UPDATE 不能直接跨表更新,得用 JOIN 或子查询
SQL 标准里 UPDATE 语句本身不支持 FROM 子句(除 PostgreSQL 和 SQL Server 外),更不允许写成 UPDATE t1, t2 SET ... 这种多表形式——MySQL 虽然语法上允许,但实际执行时仍受限于关联条件和锁机制,极易出错或被优化器拒绝。
真正可靠的做法是:用 JOIN(在支持的数据库中)或嵌套 SELECT(通用方案)把目标值“带进来”,再更新主表。不是“同时更新多个表”,而是“一次更新一个表,但值来源于其他表”。
MySQL 中用 JOIN 更新单表(最常用场景)
MySQL 允许 UPDATE ... JOIN 语法,这是日常运维中最常遇到的“伪多表更新”。注意它只修改 UPDATE 后面明确列出的那个表,其余表仅用于提供数据或过滤条件。
-
UPDATE orders o JOIN customers c ON o.customer_id = c.id SET o.status = 'shipped' WHERE c.country = 'CN'—— 只改orders表,customers表只读 - 别写成
UPDATE orders, customers SET ...:MySQL 5.7+ 默认禁用这种旧式隐式 JOIN,会报错ERROR 1109 (42S02): Unknown table 'customers' in MULTI UPDATE - 如果要基于聚合结果更新(比如“每个客户的最新订单状态”),必须先用子查询包装聚合逻辑,否则报错
You can't specify target table 't' for update in FROM clause
PostgreSQL / SQL Server 支持 FROM,但语义不同
PostgreSQL 的 UPDATE ... FROM 和 SQL Server 的 UPDATE ... FROM 看似一样,实则行为差异很大:
- PostgreSQL:
UPDATE products SET price = p2.price FROM products_backup p2 WHERE products.id = p2.id——FROM是显式关联,安全可控 - SQL Server:
UPDATE p SET p.price = p2.price FROM products p JOIN products_backup p2 ON p.id = p2.id—— 必须带别名,且FROM后不能是纯子查询(除非套一层AS) - 两者都不允许在
FROM子句里更新同一张表(即不能 self-update 加 FROM),否则死锁或不可预测
想真正在事务中更新多个表?只能分步 + 显式事务
没有数据库能原子化地“一条语句更新两个独立表”。所谓“同时”,只能靠事务保证一致性:
- 先
BEGIN TRANSACTION(或START TRANSACTION) - 依次执行多个
UPDATE,每条都只操作一张表,但用相同条件(如WHERE order_id = 123)确保逻辑一致 - 最后
COMMIT;任一失败就ROLLBACK - 注意:若涉及外键约束(如
ON UPDATE CASCADE),部分更新可能被自动触发,但这不属于你写的UPDATE语句本身的行为
很多人卡在“为什么我写了两个 UPDATE 却没生效”,其实是忘了加事务,或者第二个语句因第一个的锁未释放而超时。

















