如何在MySQL中完成一个完整的外部连接?

我想在MySQL中完成一个完全外连接。 这可能吗? MySQL是否支持完全外部联接?


你在MySQL上没有FULL JOIN,但你可以确定它们是模拟的。

对于从这个SO问题转录的代码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 set操作符以删除查询模式引入的重复行。 我们可以通过对第二个查询使用反连接模式来避免引入重复行,然后使用UNION ALL集合运算符来组合这两个集合。 在更一般的情况下,如果FULL OUTER JOIN会返回重复的行,我们可以这样做:

  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

帕布罗圣克鲁斯给出的答案是正确的; 但是,如果有人偶然发现此页面并希望得到更多解释,请参阅详细分类。

示例表

假设我们有以下表格:

-- 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 JOIN是速记LEFT 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不支持这一点。 我们可以通过执行左连接和右连接的联合来模拟它,如下所示:

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


使用union查询将删除重复项,这与full outer join的行为不同,永远不会删除任何重复项:

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

这是full outer join的预期结果:

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

这是使用leftright Join union

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相同的结果。 这篇博客文章也很好地解释了这一点 - 从方法2引用:“它正确处理重复的行,并且不包含任何它不应该的东西。有必要使用UNION ALL而不是普通的UNION ,这会消除我想要的副本保留。对于大型结果集,这可能会更有效,因为不需要对重复进行排序和删除。“


我决定添加另一个来自full outer join可视化和数学的解决方案,它不是上面更好但更易读:

完全外连接意味着(t1 ∪ t2) :全部在t1t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_onlyt1t2加上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]

链接地址: http://www.djcxy.com/p/44033.html

上一篇: How to do a FULL OUTER JOIN in MySQL?

下一篇: How can I populate ASPX Textbox controls using a SQL Inner Join statement in C#