跨表更新是什么
用另一张表的数据更新本表:PostgreSQL 写 UPDATE ... FROM,MySQL 写 UPDATE ... JOIN,语义都是按关联条件把源表的值刷到目标表。风险在于源表对同一目标行有多条匹配时,用哪一条由执行计划决定,结果不确定。
基本信息
| PostgreSQL | UPDATE 目标表 SET … FROM 源表 WHERE 关联条件 |
|---|---|
| MySQL | UPDATE 目标表 JOIN 源表 ON … SET … |
| 一对多风险 | 源表同一键有多行时取值不确定 |
| MySQL 限制 | 多表 UPDATE 不支持 ORDER BY 与 LIMIT |
| PG 注意 | 别把目标表重复写进 FROM,会变成自连接 |
| 自检方式 | 先把源表按键聚合成一行,或确认源表键唯一 |
PostgreSQL 写法
PostgreSQL 写法
UPDATE orders o
SET status = p.status,
paid_at = p.paid_at
FROM payment p
WHERE p.order_id = o.id
AND p.status = 'success'; -- 只更新有成功支付记录的订单
-- 注意:FROM 里不要再写 orders,否则会变成自连接导致结果放大MySQL 写法
MySQL 写法
UPDATE orders o
JOIN payment p ON p.order_id = o.id AND p.status = 'success'
SET o.status = p.status,
o.paid_at = p.paid_at;
-- 多表 UPDATE 不支持 ORDER BY 与 LIMIT
-- 想分批更新请改用带主键范围条件的 WHERE两库写法对照
| 需求 | PostgreSQL | MySQL |
|---|---|---|
| 单源表更新 | UPDATE … FROM 源表 WHERE 关联 | UPDATE … JOIN 源表 ON 关联 |
| 只更新匹配行 | FROM 加 WHERE 相当于内连接语义 | JOIN 默认就是内连接语义 |
| 保留未匹配行 | 未匹配行保持原值不变 | 同样只更新匹配到的行 |
| 左连接更新 | 在 FROM 中加条件或用子查询 | UPDATE … LEFT JOIN … ON … |
| 批量限制 | 可用 CTE 与子查询控制范围 | 多表 UPDATE 不支持 ORDER BY / LIMIT |
典型使用场景
- 状态回填:用支付表刷新订单的支付状态与时间
- 维表补齐:把商品名称、分类刷进明细表
- 数据修正:按对照表批量修正错误的编码
- 分层汇总:把汇总表结果刷回主表,避免每次实时计算
- 迁移过渡期双写校验:用一张表的结果校正另一张表
- 批量改价:用价格表刷新商品表的最新售价
源表一对多时先聚合再更新:把源表按关联键聚合成一行(取最大、最新一条或合计),再参与更新,结果才确定。否则同一条 SQL 两次执行可能给出不同结果。
更新前先跑一遍 SELECT 校验影响范围:把同样的关联条件写成 SELECT COUNT(*),确认待更新行数与预期一致,并确认源表关联键唯一,然后再执行 UPDATE。