ChatGPT解决这个技术问题 Extra ChatGPT

如何在 MySQL 中进行 FULL OUTER JOIN?

我想在 MySQL 中做一个 full outer join。这可能吗? MySQL 是否支持完全外连接

这个问题有更好的答案
请注意这里的答案。 SQL 标准说完全连接是行的内连接联合所有不匹配的左表行由空值扩展联合所有右表行由空值扩展。这里的大多数答案都是错误的(请参阅评论)并且没有错误的答案不能处理一般情况。即使有很多(不合理的)赞成票。 (见我的回答。)
查询不需要@JairoLozano 约束。尽管当约束持有额外的查询时会返回所需的答案,否则不会。约束不影响给定参数返回的完全连接。您描述的问题是您编写的查询是错误的查询。 (大概是人们想要一些连接的常见错误,每个可能涉及不同的键,一些子查询,每个可能涉及连接和/或聚合,但他们错误地尝试执行所有连接,然后进行所有聚合或聚合之前的聚合.)
使用 UNION 而不是 UNION ALL 的所有答案都是不正确的。所有带有子查询或 3 个联合选择的答案都是低效的。正确的答案将使用从第二个表中选择的所有左连接进行联合,其中第一个表上不存在(或等效的外连接 + where =NULL 条件)

P
Peter Mortensen

您在 MySQL 中没有完全连接,但您可以确定 emulate them

对于从 this Stack Overflow question 转录的代码sample,您有:

有两个表 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

上面的查询适用于 full outer join 操作不会产生任何重复行的特殊情况。上面的查询依赖于 UNION 集合运算符来删除查询模式引入的重复行。我们可以通过对第二个查询使用 anti-join 模式来避免引入重复行,然后使用 UNION ALL 集合运算符来组合这两个集合。在更一般的情况下,完全外连接会返回重复的行,我们可以这样做:

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

实际上你写的东西是不正确的。因为当您执行 UNION 时,您将删除重复项,有时当您连接两个不同的表时应该存在重复项。
这是正确的示例:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
所以不同之处在于我正在使用 UNION ALL 进行左包含连接,然后右排
我现在看到你自己这么说,对不起。也许您可以更新您的答案,因为在这种情况下它会出错并且 UNION ALL 总是会更有效率?
@ypercube:如果 t1t2 中没有重复的行,则此答案中的查询会返回一个模拟 FULL OUTER JOIN 的结果集。但在更一般的情况下,例如,SELECT 列表不包含足够的列/表达式来使返回的行唯一,那么这个查询模式 insufficient 来重现将由FULL OUTER JOIN。为了获得更忠实的模拟,我们需要一个 UNION ALL 集合运算符,其中一个查询需要一个 anti-join 模式。 Pavle Lekic 的评论(上图)给出了 正确的 查询模式。
C
Community

Pablo Santa Cruz 给出的答案是正确的;但是,如果有人偶然发现此页面并希望获得更多说明,这里有一个详细的细分。

示例表

假设我们有以下表格:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

内连接

内部连接,如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

只会让我们得到出现在两个表中的记录,如下所示:

1 Tim  1 Tim

内连接没有方向(如左或右),因为它们是明确的双向的——我们需要两边都匹配。

外连接

另一方面,外部联接用于查找在另一个表中可能不匹配的记录。因此,您必须指定允许连接的哪一侧有缺失记录。

LEFT JOINRIGHT JOINLEFT OUTER JOINRIGHT OUTER JOIN 的简写;我将在下面使用它们的全名来强化外连接与内连接的概念。

左外连接

左外连接,如下所示:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

...会从左表中获取所有记录,无论它们在右表中是否有匹配项,如下所示:

1 Tim   1    Tim
2 Marta NULL NULL

右外连接

右外连接,如下所示:

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

...会从右表中获取所有记录,无论它们在左表中是否有匹配项,如下所示:

1    Tim   1  Tim
NULL NULL  3  Katarina

全外连接

完全外连接将为我们提供两个表中的所有记录,无论它们在另一个表中是否有匹配项,在没有匹配项的两边都有 NULL。结果将如下所示:

1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina

然而,正如 Pablo Santa Cruz 所指出的,MySQL 不支持这一点。我们可以通过对左连接和右连接进行 UNION 来模拟它,如下所示:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

您可以将 UNION 视为“运行这两个查询,然后将结果堆叠在一起”;一些行将来自第一个查询,一些来自第二个查询。

应该注意的是,MySQL 中的 UNION 将消除完全重复的内容:Tim 将出现在此处的两个查询中,但 UNION 的结果只列出了他一次。我的数据库专家同事认为不应依赖这种行为。所以为了更明确一点,我们可以在第二个查询中添加一个 WHERE 子句:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;

另一方面,如果您出于某种原因希望查看重复项,则可以使用 UNION ALL


对于 MySQL,如果没有重叠,您真的希望避免使用 UNION 而不是 UNION ALL(请参阅上面 Pavle 的评论)。如果您可以在此处的答案中添加更多信息,我认为这将是该问题的首选答案,因为它更彻底。
“数据库大师同事”的建议是正确的。就关系模型(Ted Codd 和 Chris Date 完成的所有理论工作)而言,最后一种形式的查询模拟了 FULL OUTER JOIN,因为它结合了两个不同的集合,第二个查询不引入“重复”(第一个查询已返回的行)不会由 FULL OUTER JOIN 生成。以这种方式进行查询并使用 UNION 删除这些重复项并没有错。但要真正复制 FULL OUTER JOIN,我们需要其中一个查询是反连接。
@IstiaqueAhmed:目标是模拟 FULL OUTER JOIN 操作。我们在第二个查询中需要该条件,因此它只返回不匹配的行(反连接模式。)。没有那个条件,查询就是一个外连接......它返回匹配的行以及不匹配的行。第一个查询已经返回了匹配的行。如果第二个查询(再次)返回相同的行,我们已经复制了行,我们的结果将不等同于 FULL OUTER JOIN。
@IstiaqueAhmed:UNION 操作确实会删除这些重复项;但它也会删除所有重复的行,包括将由 FULL OUTER JOIN 返回的重复行。要模拟 a FULL JOIN b,正确的模式是 (a LEFT JOIN b) UNION ALL (b ANTI JOIN a)
非常简洁的答案,有很好的解释。谢谢你。
P
Peter Mortensen

使用联合查询将删除重复项,这与从不删除任何重复项的完全外连接的行为不同:

[Table: t1]        [Table: t2]
value              value
-----------        -------
1                  1
2                  2
4                  2
4                  5

这是完全外连接的预期结果:

value | value
------+-------
1     | 1
2     | 2
2     | 2
Null  | 5
4     | Null
4     | Null

这是将左连接和右连接与联合一起使用的结果:

value | value
------+-------
Null  | 5
1     | 1
2     | 2
4     | Null

SQL Fiddle

我建议的查询是:

select
    t1.value, t2.value
from t1
left outer join t2
  on t1.value = t2.value
union all      -- Using `union all` instead of `union`
select
    t1.value, t2.value
from t2
left outer join t1
  on t1.value = t2.value
where
    t1.value IS NULL

上述查询的结果与预期结果相同:

value | value
------+-------
1     | 1
2     | 2
2     | 2
4     | NULL
4     | NULL
NULL  | 5

SQL Fiddle

@Steve Chambers:[来自评论,非常感谢!]

注意:这可能是最好的解决方案,既能提高效率,又能产生与 FULL OUTER JOIN 相同的结果。 This blog post 也很好地解释了它 - 引用方法 2:“这可以正确处理重复的行,并且不包含任何不应该包含的内容。必须使用 UNION ALL 而不是普通的 UNION,这将消除我想保留的重复项。这在大型结果集上可能会显着提高效率,因为不需要排序和删除重复项。"

我决定添加另一个来自完全外部连接可视化和数学的解决方案。它并不比上面的好,但它更具可读性:

全外连接意味着 (t1 ∪ t2):全部在 t1 或 t2 中 (t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only:全部在 t1 和 t2 中加上所有在 t1 中但不在 t2 和加上t2 中所有不在 t1 中的:

-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value
union all  -- And plus
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)
union all  -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)

SQL Fiddle


我们正在执行相同的任务两次,如果有 t1 和 t2 的子查询,那么 mysql 必须多次执行相同的任务,不是吗?在这种情况下我们可以使用别名删除它吗?:
我建议你使用一些临时表;)。
这种方法似乎是最好的解决方案,无论是效率还是生成与 FULL OUTER JOIN 相同的结果。 This blog post 也很好地解释了它 - 引用方法 2:“这可以正确处理重复的行,并且不包含任何不应该包含的内容。有必要使用 UNION ALL 而不是普通的 UNION,这将消除重复我想保留。这在大型结果集上可能会更有效,因为不需要排序和删除重复项。"
@SteveChambers 为时已晚,但感谢您的评论。我添加了您的评论,然后回答突出显示的更多内容,如果您不同意,请回滚;)。
没问题@shA.t - IMO 这真的应该有更多的赞成票和/或被接受的答案。
P
Peter Mortensen

MySQL 没有 FULL-OUTER-JOIN 语法。您必须通过执行 LEFT JOIN 和 RIGHT JOIN 来模拟它,如下所示:

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

但是 MySQL 也没有 RIGHT JOIN 语法。根据 MySQL 的 outer join simplification,通过在查询中的 FROMON 子句中切换 t1 和 t2 将右连接转换为等效的左连接。因此,MySQL 查询优化器将原始查询转换为以下内容 -

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

现在,按原样编写原始查询并没有什么坏处,但是如果您有诸如 WHERE 子句之类的谓词,它是一个 before-join 谓词,或者是 ON 子句上的一个 AND 谓词,它是一个 during-join 谓词,那么你可能想看看魔鬼;这是详细的。

MySQL 查询优化器会定期检查谓词是否被 null 拒绝。

https://i.stack.imgur.com/NioBX.png

现在,如果您已经完成了 RIGHT JOIN,但在 t1 的列上使用了 WHERE 谓词,那么您可能会面临遇到 null 拒绝情况的风险。

例如,查询

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'

由查询优化器翻译成以下内容:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'

所以表的顺序发生了变化,但谓词仍然适用于 t1,但 t1 现在位于 'ON' 子句中。如果 t1.col1 被定义为 NOT NULL 列,那么这个查询将被 null-rejected

任何被 null 拒绝的外连接(左、右、全)都会被 MySQL 转换为内连接。

因此,您可能期望的结果可能与 MySQL 返回的结果完全不同。你可能认为它是 MySQL 的 RIGHT JOIN 的一个错误,但这是不对的。它就是 MySQL 查询优化器的工作方式。因此,负责的开发人员在构建查询时必须注意这些细微差别。


P
Peter Mortensen

之前的答案都不是真正正确的,因为当存在重复值时它们不遵循语义。

对于诸如(来自 this duplicate)的查询:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;

正确的等价物是:

SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION  -- This is intentionally UNION to remove duplicates
      SELECT name FROM t2
     ) n LEFT JOIN
     t1
     ON t1.name = n.name LEFT JOIN
     t2
     ON t2.name = n.name;

如果您需要它与 NULL 值一起使用(这也可能是必需的),则使用 NULL 安全比较运算符 <=> 而不是 =


这通常是一个很好的解决方案,但只要 name 列为空,它可能会给出与 FULL OUTER JOIN 不同的结果。具有反连接模式的 union all 查询应该正确地再现外连接行为,但哪种解决方案更合适取决于上下文和表上的活动约束。
@fthiella。 . .这是一个好点。我调整了答案。
好的,但是 null 安全的比较运算符将使联接成功,这与完整的外部联接行为不同,以防您在 t1 和 t2 中都有空名称
@fthiella。 . .我将不得不考虑最好的方法来做到这一点。但考虑到公认的答案有多么错误,几乎任何事情都更接近正确答案。 (如果两边都有多个键,那么这个答案就是错误的。)
是的,接受的答案是错误的,作为一般解决方案,我认为使用 union all 是正确的,但该答案在第一个或第二个查询中错过了一个反连接模式,该模式将保留现有的重复项,但阻止添加新的重复项。根据上下文,其他解决方案(例如这个)可能更合适。
s
shA.t

在 SQLite 中,你应该这样做:

SELECT * 
FROM leftTable lt 
LEFT JOIN rightTable rt ON lt.id = rt.lrid 
UNION
SELECT lt.*, rl.*  -- To match column set
FROM rightTable rt 
LEFT JOIN  leftTable lt ON lt.id = rt.lrid

我们可以使用它吗?如: SELECT * FROM leftTable lt LEFT JOIN rightTable rt ON lt.id = rt.lrid UNION SELECT lt.*, rl.* -- 匹配列集 FROM leftTable lt RIGHT JOIN rightTable rt ON lt.id = rt.lrid ;
是的,但 SQLite 不支持右连接,但在 MYSQL 中是的
l
lolo

您可以执行以下操作:

(SELECT 
    *
FROM
    table1 t1
        LEFT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t2.id IS NULL)
UNION ALL
 (SELECT 
    *
FROM
    table1 t1
        RIGHT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t1.id IS NULL);

一个解释将是有序的。请通过 editing (changing) your answer 回复,而不是在评论中(没有“编辑:”、“更新:”或类似内容 - 答案应该看起来好像是今天写的)。
P
Peter Mortensen

为了更清楚,我修改了 shA.t's query

-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value   

    UNION ALL -- include duplicates

-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t1.value IS NULL 

A
Alex Pliutau
SELECT
    a.name,
    b.title
FROM
    author AS a
LEFT JOIN
    book AS b
    ON a.id = b.author_id
UNION
SELECT
    a.name,
    b.title
FROM
    author AS a
RIGHT JOIN
    book AS b
    ON a.id = b.author_id

y
ysth

您可以只转换完整的外部联接,例如

SELECT fields
FROM firsttable
FULL OUTER JOIN secondtable ON joincondition

进入:

SELECT fields
FROM firsttable
LEFT JOIN secondtable ON joincondition
UNION ALL
SELECT fields (replacing any fields from firsttable with NULL)
FROM secondtable
WHERE NOT EXISTS (SELECT 1 FROM firsttable WHERE joincondition)

或者,如果您在 firsttable 中至少有一列(例如 foo)不为 NULL,则可以执行以下操作:

SELECT fields
FROM firsttable
LEFT JOIN secondtable ON joincondition
UNION ALL
SELECT fields
FROM firsttable
RIGHT JOIN secondtable ON joincondition
WHERE firsttable.foo IS NULL

P
Peter Mortensen

我修复了响应,并且工作包括所有行(基于 Pavle Lekic 的响应):

    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    WHERE b.`key` is null
    )
    UNION ALL
    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    where  a.`key` = b.`key`
    )
    UNION ALL
    (
    SELECT b.* FROM tablea a
    right JOIN tableb b ON b.`key` = a.key
    WHERE a.`key` is null
    );

不,这是一种“仅限外部”连接,它只会返回 tablea 中在 tableb 中没有匹配的行,反之亦然。您尝试 UNION ALL,这仅在这两个表具有等价列的情况下才有效,这不能保证。
它有效,我在临时数据库 tablea(1,2,3,4,5,6) 和 tableb(4,5,6,7,8,9) 上创建它的行有 3 个列“id”、“number”和"name_number" 作为文本,结果只有 (1,2,3,7,8,9)
这不是外部连接。外连接还包括匹配的成员。
那个新句子的所有结果都是 1,2, ..., 9
这几乎是难以理解的(“我修复了响应,并且作品包括所有行”)。你可以fix it吗? (但没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的。)
P
Peter Mortensen

利用:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;

它可以重新创建如下:

 SELECT t1.*, t2.*
 FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
 LEFT JOIN t1 ON t1.id = tmp.id
 LEFT JOIN t2 ON t2.id = tmp.id;

使用 UNION 或 UNION ALL 答案不涵盖基表具有重复条目的边缘情况。

解释:

有一个 UNION 或 UNION ALL 无法覆盖的边缘情况。我们无法在 MySQL 上测试它,因为它不支持完全外连接,但我们可以在支持它的数据库上说明这一点:

 WITH cte_t1 AS
 (
     SELECT 1 AS id1
     UNION ALL SELECT 2
     UNION ALL SELECT 5
     UNION ALL SELECT 6
     UNION ALL SELECT 6
 ),
cte_t2 AS
(
     SELECT 3 AS id2
     UNION ALL SELECT 4
     UNION ALL SELECT 5
     UNION ALL SELECT 6
     UNION ALL SELECT 6
)
SELECT  *  FROM  cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;

This gives us this answer:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

UNION 解决方案:

SELECT  * FROM  cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION    
SELECT  * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

给出一个错误的答案:

 id1  id2
NULL  3
NULL  4
1  NULL
2  NULL
5  5
6  6

UNION ALL 解决方案:

SELECT  * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT  * FROM  cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

也是不正确的。

id1  id2
1  NULL
2  NULL
5  5
6  6
6  6
6  6
6  6
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

而这个查询:

SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
LEFT JOIN t1 ON t1.id = tmp.id
LEFT JOIN t2 ON t2.id = tmp.id;

给出以下内容:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

顺序不同,但在其他方面与正确答案匹配。


这很可爱,但歪曲了 UNION ALL 解决方案。此外,它还提供了一个使用 UNION 的解决方案,由于需要重复数据删除,该解决方案在大型源表上会变慢。最后,它不会编译,因为子查询 tmp 中不存在字段 id
我从来没有对速度提出任何要求,OP也没有提到任何关于速度的内容。假设 UNION ALL (你不依赖指定哪一个)并且这两个都给出了正确的答案,如果我们想断言一个更快,我们需要提供基准,这将偏离 OP问题。
至于关于 id 不在子查询中的观察,我更正了错字 - 感谢您指出。您的虚假陈述声明含糊不清 - 如果您可以提供更多信息,我可以解决这个问题。关于你对可爱的最后观察,我没有任何评论,我宁愿专注于sql的逻辑。
歪曲:“UNION ALL 解决方案:……也不正确。”您提供的代码省略了必须在 UNION ALL 中提供的右连接 (where t1.id1 is null) 的交集排除。也就是说,您的解决方案胜过所有其他解决方案,只有当其中一个解决方案实施不正确时。关于“可爱”的观点。那是无缘无故的,我很抱歉。
P
Peter Mortensen

使用 cross join 解决方案:

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;

不,这是交叉连接。它将 t1 中的每一行与 t2 中的每一行匹配,产生所有可能组合的集合,结果集中有 select (select count(*) from t1) * (select count(*) from t2)) 行。
虽然此代码可能会回答问题,但提供有关其解决问题的方式和原因的额外上下文将提高答案的长期价值。
哪个补充可能有帮助?也许是例子?
a
alamelu

这也是可能的,但您必须在选择中提及相同的字段名称。

SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id

这只是复制左连接的结果。
这不会给出与完全外连接等效的结果。
p
philipxy

SQL 标准说 full join oninner join onunion all 由空值扩展的不匹配左表行 union all 由空值扩展的右表行。即 left join on 中的 inner join onunion all 行但不是 inner join on right join on 中的 union all 行但不是 inner join on

left join onunion all right join on 行不在 inner join on 中。或者,如果您知道您的 inner join on 结果在特定的右表列中不能为 null,则“right join on 行不在 inner join on 中”是 right join on 中的行,其中 on 条件由 and 扩展is null 列。

即同样right join on union all 适当的left join on 行。

What is the difference between “INNER JOIN” and “OUTER JOIN”?

(SQL Standard 2006 SQL/Foundation 7.7 语法规则 1、一般规则 1 b、3 c & d、5 b。)


这似乎是部分难以理解的(例如,“完全连接是行内连接联合所有不匹配的左表行由空值扩展联合所有右表行由空值扩展。”)。你能改写吗?
@PeterMortensen 我很快就会编辑这篇文章。 FULL JOIN ON 返回 <行 INNER JOIN ON 返回> UNION ALL <通过获取未参与 INNER JOIN 的左表行并为每个右表列使用 NULL 扩展它们获得的行> UNION ALL 。当然,任何人都应该清楚措辞。但是,如果您知道 FULL JOIN ON 返回什么,我会觉得很奇怪,您无法按原样解析它。
@PeterMortensen 你的逗号改变了意思,所以我把它们回滚了。但我将进行编辑以澄清。