MySQL需显式写INNER/LEFT JOIN;PostgreSQL用UPDATE...FROM模拟连接,默认内连接;SQL Server要求目标表在UPDATE和FROM中均出现且用别名。

MySQL 的 UPDATE JOIN:JOIN 写在 UPDATE 后,别漏 INNER
MySQL 允许直接在 UPDATE 后跟 JOIN,但必须显式写出连接类型(INNER JOIN 或 LEFT JOIN),不能省略。很多人照搬 SELECT 习惯写 UPDATE t1 JOIN t2 ON ...,结果报错——因为 MySQL 要求明确是 INNER JOIN 还是 LEFT JOIN。
-
UPDATE后只能列目标表(被更新的表),其他表必须出现在JOIN子句中 - 别用逗号隐式连接 + WHERE 的老写法(如
UPDATE t1, t2 SET ... WHERE t1.id = t2.id),虽然能跑,但可读性差、易出错,且不支持LEFT JOIN逻辑 - WHERE 条件里不能引用未 JOIN 的表;如果想过滤源表字段(比如只更新 VIP 客户订单),条件必须写在
WHERE,而不是ON - 示例:
UPDATE orders o INNER JOIN customers c ON o.customer_id = c.id SET o.discount = 0.2 WHERE c.level = 'VIP'
PostgreSQL 的 UPDATE FROM:没有 JOIN 关键字,靠 FROM + WHERE 模拟连接
PostgreSQL 不支持 UPDATE ... JOIN 语法,它用 UPDATE ... FROM 实现等效功能,本质是把关联表“拉进来”,再靠 WHERE 做匹配。这容易让人误以为是 LEFT JOIN,其实默认是内连接语义——没匹配上的行根本不会进更新范围。
-
FROM后可以写子查询或带别名的表,但目标表不能在FROM中重复出现(比如不能写UPDATE t1 FROM t1 ...) - 想实现“无匹配也更新为 NULL”的效果,得用
LEFT JOIN包裹在子查询里,例如:UPDATE employees SET dept_name = d.dept_name FROM (SELECT id, dept_name FROM departments) AS d WHERE employees.dept_id = d.id,再配合COALESCE或单独处理空值 - 如果连接条件不唯一(比如多个部门同名),PostgreSQL 可能随机选一行更新,结果不可控——务必确保
ON字段有唯一约束或加聚合 - 示例:
UPDATE employees SET dept_name = d.dept_name FROM departments d WHERE employees.dept_id = d.id
SQL Server 的 UPDATE FROM:FROM 在 SET 前,目标表别名必须出现两次
SQL Server 要求目标表在 UPDATE 和 FROM 中都出现,且必须用别名。常见错误是只在 UPDATE 后写别名,忘了在 FROM 里再声明一次,导致“无效的对象名”或列绑定失败。
-
UPDATE t1 SET ... FROM t1 JOIN t2 ...是标准写法,t1必须在FROM中作为参与连接的一方出现 - 不支持
UPDATE ... JOIN ... SET这种 MySQL 风格,也不接受 PostgreSQL 的纯FROM table写法 - 可以用逗号分隔表名模拟隐式连接(
FROM t1, t2 WHERE t1.id = t2.id),但推荐显式JOIN,避免歧义和性能问题 - LEFT JOIN 场景下,
SET中若引用右表字段,需用ISNULL(t2.col, default)处理 NULL,否则整行更新会跳过(因 NULL 参与比较结果为 UNKNOWN) - 示例:
UPDATE s SET s.score = sc.score FROM students s INNER JOIN scores sc ON s.id = sc.id
跨库迁移时最容易翻车的三个点
语法只是表象,真正卡住人的是语义差异和隐含行为。比如同样一条“用部门表更新员工部门名”的逻辑,在三者中执行结果可能不同。
- MySQL 的
LEFT JOIN在UPDATE中会更新所有左表行,哪怕右表没匹配——PostgreSQL 和 SQL Server 默认都不会,除非你额外补逻辑 - PostgreSQL 的
FROM子句不支持直接写LEFT JOIN departments ON ...,必须包装成子查询或用LATERAL(v12+),否则报错 - SQL Server 对更新目标表的锁定更激进,多表 JOIN 更新时容易阻塞其他事务;而 MySQL 在 RR 隔离级别下可能产生间隙锁,影响并发
- 所有数据库都不允许在
SET中更新FROM表的字段(即不能SET t2.col = ...),只允许改目标表——这点常被忽略,尤其从 SELECT 改写过来时
SELECT ... INTO TEMP 或应用层缓存中间数据,再单表更新。










