Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在MySQL中进行完整的外部连接?_Sql_Mysql_Join_Outer Join_Full Outer Join - Fatal编程技术网

如何在MySQL中进行完整的外部连接?

如何在MySQL中进行完整的外部连接?,sql,mysql,join,outer-join,full-outer-join,Sql,Mysql,Join,Outer Join,Full Outer Join,我想在MySQL中做一个完整的外部连接。这可能吗?MySQL支持完全外部联接吗?您在MySQL上没有完全联接,但可以确定 对于从中转录的代码示例,您有: 有两个表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 上述查询适用于完全外部联接操作不会产生任何重复行的特殊情况。上面的查询依赖于UNIONset操作符来删除查询模式引入的

我想在MySQL中做一个完整的外部连接。这可能吗?MySQL支持完全外部联接吗?

您在MySQL上没有完全联接,但可以确定

对于从中转录的代码示例,您有:

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

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

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
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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`;
将仅获取两个表中出现的记录,如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
1 Tim  1 Tim
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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`;
内部连接没有方向(如左或右),因为它们是显式双向的-我们需要在两侧进行匹配

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

左连接
右连接
左外连接
右外连接
的缩写;下面我将使用它们的全名来强化外部联接与内部联接的概念

左外连接 左外连接,如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
1 Tim  1 Tim
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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`;
…将从左表中获取所有记录,无论右表中是否有匹配项,如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
1 Tim  1 Tim
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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`;
右外连接 右外连接,如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
1 Tim  1 Tim
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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`;
…将从右表中获取所有记录,无论左表中是否有匹配项,如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
1 Tim  1 Tim
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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`;
完全外接 一个完整的外部联接将为我们提供两个表中的所有记录,无论它们在另一个表中是否匹配,在不匹配的两侧都为null。结果如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
1 Tim  1 Tim
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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`;
然而,正如PabloSanta Cruz所指出的,MySQL不支持这一点。我们可以通过左连接和右连接的并集来模拟它,如下所示:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
1 Tim  1 Tim
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
1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina
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;

另一方面,如果出于某种原因希望看到重复项,可以在SQLite中使用
UNION ALL

,您应该这样做:

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中提及相同的字段名

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

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

[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

我的建议是:

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


:[来自评论,非常感谢!]
注意:从效率和生成与
完全外部联接相同的结果两方面考虑,这可能是最好的解决方案。也很好地解释了这一点——引用方法2:“这将正确处理重复的行,并且不包含任何不应该包含的内容。有必要使用
UNION ALL
而不是普通的
UNION
,这将消除我想要保留的重复项。这在大型结果集上可能更有效,因为不需要排序和删除重复项。”


我决定添加另一个解决方案,该解决方案来自
完全外部连接
可视化和数学,这并不是更好,而是更具可读性:

完全外部连接意味着
(t1∪ t2)
:全部在
t1
t2

(t1∪ t2)=(t1∩ t2)+t1_only+t2_only
:全部在
t1
t2
中加上全部在
t1
中不在
t2
中加上全部在
t2
中不在
t1
中:


为了更加清晰,修改了shA.t的查询:

-- 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 

上述答案实际上都不正确,因为它们在存在重复值时不遵循语义

对于查询,例如(来自此):

正确的等价物是:

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
-安全比较运算符
,而不是
=

回答:

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答案不包括基表具有重复项的边缘情况

说明:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;
有一种边缘情况,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
欧盟解决方案:

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
欧盟所有解决方案:

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
(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);
顺序不同,但在其他方面与正确答案相匹配。

我修复了响应,并且