SQL标准不支持三表链式FULL JOIN,因语义模糊;可用UNION ALL+LEFT JOIN模拟六种行组合,或括号嵌套FULL JOIN并谨慎处理NULL传播。

SQL标准不支持直接写 FULL JOIN 多表链式语法
几乎所有主流数据库(PostgreSQL、SQL Server、Oracle)都只允许两个表之间用 FULL JOIN,写成 SELECT * FROM a FULL JOIN b ON ... FULL JOIN c ON ... 会报语法错误——比如 PostgreSQL 报 ERROR: FULL JOIN is only supported with two tables,SQL Server 则直接拒绝解析。
根本原因在于 FULL JOIN 的语义是“保留左表和右表所有行”,当引入第三张表时,中间结果集已含 NULL 行,再与第三表做 FULL JOIN 会导致语义模糊:对中间结果里的 NULL 行,该不该算作“左表存在”?标准 SQL 没定义这种嵌套行为,所以干脆禁止。
用 UNION ALL + LEFT JOIN 模拟三表 FULL JOIN
核心思路是把三张表的“独有行”和“共有的交集行”分别捞出来,再拼一起。关键不是连表,而是覆盖所有可能的行来源组合:
-
表A独有:A中存在,但B和C中都无匹配(用两次LEFT JOIN+IS NULL判定) -
表B独有:同理,B存在,A和C均无匹配 -
表C独有:C存在,A和B均无匹配 -
A&B共有但C无:A和B能连上,但C没匹配到 -
A&C共有但B无:类似 -
B&C共有但A无:类似 -
A&B&C全有:三表都能通过关联条件连上
示例(以 id 为关联字段):
SELECT a.id, a.name AS a_name, b.name AS b_name, c.name AS c_name FROM a LEFT JOIN b ON a.id = b.id LEFT JOIN c ON a.id = c.id WHERE b.id IS NULL AND c.id IS NULL -- A独有 <p>UNION ALL</p><p>SELECT b.id, NULL, b.name, NULL FROM b LEFT JOIN a ON b.id = a.id LEFT JOIN c ON b.id = c.id WHERE a.id IS NULL AND c.id IS NULL -- B独有</p><p>UNION ALL</p><p>SELECT c.id, NULL, NULL, c.name FROM c LEFT JOIN a ON c.id = a.id LEFT JOIN b ON c.id = b.id WHERE a.id IS NULL AND b.id IS NULL -- C独有</p><p>UNION ALL</p><p>SELECT a.id, a.name, b.name, NULL FROM a INNER JOIN b ON a.id = b.id LEFT JOIN c ON a.id = c.id WHERE c.id IS NULL -- A&B有,C无</p><p>-- 后续补上 A&C有/B&C有/三者都有 的 UNION 分支...
用 FULL JOIN 两两嵌套时必须显式括号并处理 NULL 传播
某些数据库(如 PostgreSQL 14+)允许写 (a FULL JOIN b) FULL JOIN c,但括号不能省——否则解析器会按左结合误判。更麻烦的是,中间 FULL JOIN 结果里已有 NULL,再跟第三表 FULL JOIN 时,这些 NULL 会被当作“左表存在”参与匹配,导致重复或漏行。
实际要加一层子查询过滤中间 NULL:
SELECT coalesce(t.id, c.id) AS id,
t.a_name, t.b_name, c.name AS c_name
FROM (
SELECT coalesce(a.id, b.id) AS id, a.name AS a_name, b.name AS b_name
FROM a
FULL JOIN b ON a.id = b.id
) AS t
FULL JOIN c ON t.id = c.id;但注意:coalesce(a.id, b.id) 在 A 和 B 都为 NULL 时仍为 NULL,此时 FULL JOIN c 会把 c 的行也拉进来——这符合 FULL JOIN 语义,但未必是你想要的“三表对齐”逻辑。
业务场景决定是否真需要 FULL JOIN,多数时候 LEFT JOIN 更安全
真正需要三表 FULL JOIN 的场景极少,常见于数据治理中对比三份独立源系统的主键覆盖情况。但生产环境更常遇到的是:某张表是主事实表,另两张是可选维度表——这时应该用 fact LEFT JOIN dim1 ON ... LEFT JOIN dim2 ON ...,既简洁又避免 NULL 行爆炸。
如果硬要模拟 FULL JOIN,务必检查每张表的关联字段是否允许 NULL、是否有重复键、以及 NULL 值在业务上代表“缺失”还是“未知”。一个没处理好的 IS NULL 判断,可能让某张表的全部 NULL 主键行被当成“独有行”重复计入结果。

















