为啥 MySQL 会在 FULL OUTER JOIN 上报告语法错误?

Posted

技术标签:

【中文标题】为啥 MySQL 会在 FULL OUTER JOIN 上报告语法错误?【英文标题】:Why does MySQL report a syntax error on FULL OUTER JOIN?为什么 MySQL 会在 FULL OUTER JOIN 上报告语法错误? 【发布时间】:2011-01-23 23:12:08 【问题描述】:
SELECT airline, airports.icao_code, continent, country, province, city, website 

FROM airlines 
FULL OUTER JOIN airports ON airlines.iaco_code = airports.iaco_code
FULL OUTER JOIN cities ON airports.city_id = cities.city_id
FULL OUTER JOIN provinces ON cities.province_id = provinces.province_id
FULL OUTER JOIN countries ON cities.country_id = countries.country_id
FULL OUTER JOIN continents ON countries.continent_id = continents.continent_id

上面写着

您的 SQL 语法有错误;检查与您的 mysql 服务器版本相对应的手册,以获取正确的语法,以便在航司.iaco_code = airports.iaco_code 上的 'outer join airports 附近使用 第 4 行的全外连接

语法对我来说很合适。我以前从未做过很多连接,但我需要一个表中的这些列,这些列由各种 id 交叉引用。

【问题讨论】:

没有FULL OUTER JOIN 语法:dev.mysql.com/doc/refman/5.0/en/join.html 【参考方案1】:

MySQL 中没有FULL OUTER JOIN。见7.2.12. Outer Join Simplification和12.2.8.1. JOIN Syntax:

您可以使用 FULL OUTER JOIN 模拟 UNION(从 MySQL 4.0.0 开始):

有两个表t1,t2:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

三个表 t1、t2、t3:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
RIGHT JOIN t3 ON t2.id = t3.id

【讨论】:

有没有关于连接的教程推荐? 您的答案并不完全正确,请参阅Xelrach's answer 或this comment。 @Cletus,我在他们共享的 PK 列上不断收到“列名重复”错误...【参考方案2】:

cletus 的回答不太正确。 UNION 将删除 FULL OUTER JOIN 将包含的重复记录。如果您需要重复使用类似的东西:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
LEFT JOIN t4 ON t3.id = t4.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
LEFT JOIN t4 ON t3.id = t4.id
WHERE t1.id IS NULL
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
RIGHT JOIN t3 ON t2.id = t3.id
LEFT JOIN t4 ON t3.id = t4.id
WHERE t2.id IS NULL
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
RIGHT JOIN t3 ON t2.id = t3.id
RIGHT JOIN t4 ON t3.id = t4.id
WHERE t3.id IS NULL;

【讨论】:

请注意 - 如果你足够迂腐和理论 - 这也不是一个完美的解决方案。这种方法(使用UNION ALL,但检查JOINed 表之一中的一列是否为NULL 以识别它不能与其他表中的任何行匹配)依赖于实际具有的表至少一个NOT NULL 列。如果没有保证列实际上不包含NULL,则此方法将不起作用。 @MarkAmery:你提出了一个很好的观点。为了使反连接正常工作,WHERE 子句中的谓词需要引用我们知道(我们是保证)的列或表达式,如果满足以下条件,则不会为 NULL找到匹配的行。在使用 相等 比较的连接谓词的特殊情况下,该相等比较向我们保证该列的值对于匹配的行不会为 NULL。不必进行相等比较即可为我们提供保证。如果连接确实允许“匹配”行的 NULL 值,我们必须找到/使用非 NULL 表达式。 @MarkAmery:此查询不依赖于具有 NOT NULL 列的表。相反,此查询依赖于连接谓词(ON 子句中的条件)来保证“匹配”行中的列的非 NULL 值。这依赖于与 NULL 值一起使用时 相等比较 运算符的行为。 (我们知道foo = NULL 不会返回TRUE,即使foo IS NULL。) 希望mysql能加这个。可能只有 5 行 C 代码。我们每个人都必须多次编写这 5 行额外的代码。使用 mysql 的人看到这个应该认为这是一个功能请求。【参考方案3】:

需要FULL OUTER JOIN三个表t1、t2、t3的时候就补充一下。您可以依次将 t1、t2、t3 左连接其余两个表,然后联合。

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t1.id = t3.id
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
LEFT JOIN t3 ON t2.id = t3.id
UNION
SELECT * FROM t3
LEFT JOIN t1 ON t3.id = t1.id
LEFT JOIN t2 ON t3.id = t2.id

【讨论】:

【参考方案4】:

我刚刚为此做了一个技巧:

(select 1 from DUAL) d
LEFT OUTER JOIN t1 ON t1.id = t2.id
LEFT OUTER JOIN t2 ON t1.id = t2.id

关键是,来自 dual 的查询是一个固定点,mysql 可以将其他 2 个表外部连接到该点

【讨论】:

但此时未声明 t2JOIN t1 ON t1.id = t2.id

以上是关于为啥 MySQL 会在 FULL OUTER JOIN 上报告语法错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MySQL 中进行 FULL OUTER JOIN?

如何在 MySQL 中进行 FULL OUTER JOIN?

如何在 MySQL 中进行 FULL OUTER JOIN?

MySQL:FULL OUTER JOIN - 如何合并一列?

在 MySQL 中执行 FULL OUTER JOIN 查询时出错 [重复]

MySQL中没有FULL OUTER JOIN的处理