财务要对账:订单表一万二千条,流水表一万一千条,想一次查出两边对不上的记录。照着教程写了 full outer join,MySQL 8.0 直接报 1064,语法错误。

不是写错了。MySQL 到现在也不支持 full outer join,标准写法在 Oracle、PostgreSQL、SQL Server 里能用,换到 MySQL 就得绕。

先用 union 拼一个全外连接

左连接查左表全部,右连接查右表独有的部分,两段用 union 合起来:

SELECT a.id, a.amount, b.amount FROM orders a LEFT JOIN pay b ON a.id = b.order_id UNION SELECT a.id, a.amount, b.amount FROM orders a RIGHT JOIN pay b ON a.id = b.order_id

union 会去重并排序,数据量大时慢;两边主键确定不重复,换成 union all 快很多。

对账其实分开查更清楚

只在订单表、不在流水表的记录,left join 后加 where b.order_id is null。只在流水表、没有订单的,right join 后加 where a.id is null。两类记录分开导出,核对时一眼能看出是漏单还是多单。

要统计差异金额,用 coalesce 把空值补 0 再相减,别让 null 把整行结果带偏。

其他数据库怎么写

Oracle 和 SQL Server 直接用全外连接,PostgreSQL 同样支持。Oracle 老代码里还有用加号写外连接的,可读性差,新代码别学。

Hive、Spark SQL 一般也支持,但数据倾斜时要留意,null 键会集中到一个 reducer。

性能上的两个提醒

连接字段两边都要有索引,否则大表 join 会走全表扫描。字段类型和字符集要一致,一边 int 一边 varchar,索引直接失效。

结论:MySQL 里没有 full outer join,union 两段是最稳的替代;对账场景干脆拆成两条查询,比硬拼一个全连接好维护。