“INNER JOIN”和“OUTER JOIN”有什么区别?

What is the difference between "INNER JOIN" and "OUTER JOIN"?

提问人:Chris de Vries 提问时间:9/2/2008 最后编辑:SuperStormerChris de Vries 更新时间:10/4/2022 访问量:2606779

问:

另外,如何适应 、 和 适应?LEFT OUTER JOINRIGHT OUTER JOINFULL OUTER JOIN

sql 内部连接 outer-join

评论

89赞 philipxy 10/19/2014
在下面的答案、评论和参考文献中,只有一个实际上解释了维恩图如何表示运算符:圆相交区域表示 A JOIN B 中的行集。每个圆圈的唯一区域表示通过获取其表中不参与 A 的行、JOIN B 并将其他表的唯一列(全部设置为 NULL)获得的行集。(大多数都给出了 A 和 B 的圆圈的模糊虚假对应关系。
22赞 philipxy 5/18/2017
@DanteTheSmith 不,这与这里的图表存在相同的问题。请参阅我上面的评论,以及下面的博客文章:“杰夫在评论中拒绝了他的博客几页”。维恩图以集合的形式显示元素。只需尝试准确识别这些图中的集合是什么以及元素是什么。集合不是表,元素不是它们的行。此外,任何两个表都可以联接,因此PK和FK是不可依赖的。都是假的。你正在做成千上万的人做过的事情——你(错误地)认为有一种模糊的印象是有道理的。
2赞 philipxy 1/24/2021
我之前的评论是关于一篇令人困惑的被拒绝的杰夫·阿特伍德博客文章
2赞 philipxy 2/27/2021
我的第一条评论的链接是外部的,但 i.stack.imgur.com 有内部、左侧完整连接(绿色)的输出(非输入)插图的永久副本。

答:

127赞 1800 INFORMATION 9/2/2008 #1

仅当联接的另一侧(右侧)有匹配的记录时,内部联接才会显示行。

(左侧)外部联接在左侧显示每条记录的行,即使联接的另一侧(右侧)没有匹配的行也是如此。如果没有匹配的行,则另一侧(右侧)的列将显示 NULL。

101赞 Brian Boatright 9/2/2008 #2

内部联接要求联接表中存在具有相关 ID 的记录。

外部联接将返回左侧的记录,即使右侧不存在任何记录。

例如,您有一个 Orders 和一个 OrderDetails 表。它们通过“OrderID”关联。

订单

  • 订单 ID
  • 客户名称

订单详情

  • 订单详细信息 ID
  • 订单 ID
  • 产品名称
  • 数量
  • 价格

请求

SELECT Orders.OrderID, Orders.CustomerName
  FROM Orders 
 INNER JOIN OrderDetails
    ON Orders.OrderID = OrderDetails.OrderID

将仅返回 OrderDetails 表中也有内容的 Orders。

如果将其更改为 OUTER LEFT JOIN

SELECT Orders.OrderID, Orders.CustomerName
  FROM Orders 
  LEFT JOIN OrderDetails
    ON Orders.OrderID = OrderDetails.OrderID

然后,它将从 Orders 表返回记录,即使它们没有 OrderDetails 记录。

您可以使用它来查找没有任何 OrderDetails 的订单,这些订单指示可能的孤立订单,方法是添加类似 的 where 子句。WHERE OrderDetails.OrderID IS NULL

评论

1赞 PhiLho 1/5/2013
我很欣赏这个简单而现实的例子。我成功地将请求更改为(MySQL)。我不确定附加条件,它们混合得很好......SELECT c.id, c.status, cd.name, c.parent_id, cd.description, c.image FROM categories c, categories_description cd WHERE c.id = cd.categories_id AND c.status = 1 AND cd.language_id = 2 ORDER BY c.parent_id ASCSELECT c.id, c.status, cd.name, c.parent_id, cd.description, c.image FROM categories c INNER JOIN categories_description cd ON c.id = cd.categories_id WHERE c.status = 1 AND cd.language_id = 2 ORDER BY c.parent_id ASC
6676赞 Mark Harrison 9/2/2008 #3

假设您正在联接没有重复项的列,这是一个非常常见的情况:

  • A 和 B 的内部连接给出了 A 与 B 相交的结果,即维恩图相交的内部部分。

  • A 和 B 的外部连接给出了 A 并集 B 的结果,即维恩图并集的外部部分。

例子

假设您有两个表,每个表有一列,数据如下所示:

A    B
-    -
1    3
2    4
3    5
4    6

请注意,(1,2) 是 A 独有的,(3,4) 是通用的,(5,6) 是 B 独有的。

内部联接

使用任一等效查询的内部联接给出了两个表的交集,即它们共有的两行。

select * from a INNER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b;

a | b
--+--
3 | 3
4 | 4

左外连接

左外联接将给出 A 中的所有行,以及 B 中的任何公共行。

select * from a LEFT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a = b.b(+);

a |  b
--+-----
1 | null
2 | null
3 |    3
4 |    4

右外连接

右外连接将给出 B 中的所有行,以及 A 中的任何公共行。

select * from a RIGHT OUTER JOIN b on a.a = b.b;
select a.*, b.*  from a,b where a.a(+) = b.b;

a    |  b
-----+----
3    |  3
4    |  4
null |  5
null |  6

完全外部连接

完整的外部连接将为您提供 A 和 B 的并集,即 A 中的所有行和 B 中的所有行。如果 A 中的某些内容在 B 中没有相应的基准面,则 B 部分为 null,反之亦然。

select * from a FULL OUTER JOIN b on a.a = b.b;

 a   |  b
-----+-----
   1 | null
   2 | null
   3 |    3
   4 |    4
null |    6
null |    5

评论

67赞 softveda 8/30/2009
最好通过在表 B 中添加另一行值为 4 来扩充该示例。这将表明内部连接不必与行数相等。
535赞 Thomas 5/4/2011
然而,这是一个很好的解释:A 和 B 的外部连接给出了 A 并集 B 的结果,即维恩图并集的外部部分。 措辞不准确。除了以下一项之外,外部连接还将给出 A 与 B 相交的结果:全部 A(左连接)、全部 B(右连接)或全部 A 和全部 B(完全连接)。只有最后一种情况是真正的 A 联合 B。不过,一个写得很好的解释。
11赞 Mark Harrison 3/5/2013
@Ameer,谢谢。Join 不保证订单,您需要添加 ORDER BY 子句。
10赞 Chris 1/30/2019
@Damian,OUTER JOIN 和 FULL OUTER JOIN 是等价的,而 LEFT/RIGHT JOIN 等价于 LEFT/RIGHT OUTER JOIN,就像 INNER JOIN 等价于简单的 JOIN 一样
13赞 Colm Bhandal 5/3/2020
我对此投了反对票,因为它是错误的。请考虑删除答案,因为它会误导几代被大量 upcote 所愚弄的计算机科学专业学生。维恩图不解释连接。连接的内部部分不是交点。
68赞 naga 9/2/2010 #4

INNER JOIN要求在比较两个表时至少匹配。例如,表 A 和表 B 表示 A ٨ B(A 交集 B)。

LEFT OUTER JOIN并且是一样的。它给出了两个表中的所有匹配记录以及左侧表的所有可能性。LEFT JOIN

同样,并且是相同的。它给出了两个表中的所有匹配记录以及正确表的所有可能性。RIGHT OUTER JOINRIGHT JOIN

FULL JOIN是重复和不重复的组合。LEFT OUTER JOINRIGHT OUTER JOIN

69赞 vijikumar 9/27/2012 #5

使用 INNER JOIN 返回两个表中存在匹配项的所有行。即在结果表中,所有行和列都将具有值。

OUTER JOIN 中,生成的表可能具有空列。外部连接可以是 或 。LEFTRIGHT

LEFT OUTER JOIN 返回第一个表中的所有行,即使第二个表中没有匹配项也是如此。

RIGHT OUTER JOIN 返回第二个表中的所有行,即使第一个表中没有匹配项也是如此。

131赞 vidyadhar 1/12/2013 #6

简单来说:

内部联接仅检索匹配的行。

外部联接从一个表中检索匹配的行,并在另一个表中检索所有行。结果取决于您使用的是哪一个:

  • 左:右表中的匹配行和表中的所有行

  • 右:左表中的匹配行和表中的所有行,或者

  • 完整:所有表中的所有行。有没有匹配并不重要

评论

2赞 philipxy 11/29/2015
@nomen 并不是说这个答案解决了这个问题,但是如果左和右集/圆圈包含(分别)左和右联接的行,则 INNER JOIN 是一个交集,而 FULL OUTER JOIN 是相应的 UNION。PS 这个答案不清楚输入与输出中的行。它将“在左/右表中”与“在左/右表中有一个左/右部分”混淆,并使用“匹配行”与“全部”来表示从其他表逐行扩展的行与空值。
34赞 Lajos Veres 11/17/2013 #7

我在其他答案中没有看到有关性能和优化器的太多细节。

有时很高兴知道 only 是关联的,这意味着优化器有最多的选择来使用它。它可以对联接顺序进行重新排序,使其更快,保持相同的结果。优化器可以使用最多的联接模式。INNER JOIN

通常,尝试使用不同类型的联接来代替是一种很好的做法。(当然,如果可能的话,请考虑预期的结果集。INNER JOIN

关于这种奇怪的联想行为,这里有几个很好的例子和解释:

评论

5赞 Ben 12/26/2014
使用一种类型的联接而不是另一种类型的联接不可能是“好的做法”。您使用的联接决定了所需的数据。如果你使用不同的,你就错了。另外,至少在甲骨文中,这个答案是完全错误的。这听起来完全是错误的,你没有证据。你有证据吗?
1赞 Lajos Veres 12/26/2014
1.我的意思是尝试使用。我看到很多人在没有任何充分理由的情况下到处使用 LEFT OUTER 连接。(联接的列为“not null”。在这些情况下,使用 INNER 连接肯定会更好。2. 我添加了一个链接,比我所能更好地解释非关联行为。
0赞 shA.t 5/13/2015
据我所知,它比大多数时候都慢,人们可以使用而不是通过添加一个来消除意外结果;)。INNER JOINLEFT JOINLEFT JOININNER JOINWHERENULL
174赞 Tushar Gupta - curioustushar 1/27/2014 #8

内部连接

仅检索匹配的行,即 .A intersect B

Enter image description here

SELECT *
FROM dbo.Students S
INNER JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

左外连接

选择第一个表中的所有记录,以及第二个表中的任何记录 与联接键匹配的表。

Enter image description here

SELECT *
FROM dbo.Students S
LEFT JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

完全外部连接

选择第二个表中的所有记录,以及第一个表中的任何记录 与联接键匹配的表。

Enter image description here

SELECT *
FROM dbo.Students S
FULL JOIN dbo.Advisors A
    ON S.Advisor_ID = A.Advisor_ID

引用

评论

16赞 Grijesh Chauhan 1/27/2014
工具的名称是什么?我发现它很有趣,因为它显示了行数和维恩图
3赞 Tushar Gupta - curioustushar 1/27/2014
@GrijeshChauhan 是的,但是你可以尝试使用wine来运行它。
2赞 Grijesh Chauhan 1/27/2014
哦!是的,我..我用葡萄酒使用SQLyog。还有PlayOnLinux
3赞 philipxy 7/24/2018
你的文字不清楚和错误。“仅匹配行”是 A 和 B 的交叉连接中的行,检索到的内容(A 内部连接 B)不是 A 与 B 相交,而是 (A 左连接 B) 相交(A 右连接 B)。“选定”的行不是来自 A 和 B,而是来自 A 交叉连接 B 和 A 和 B 行的 null 扩展值。
1赞 Manuel Jordan 10/17/2019
@TusharGupta好奇的tushar,你应该包括“用于SQL示例的表”
45赞 Kanwar Singh 4/11/2014 #9

内部联接。

联接是合并两个表中的行。内部联接会尝试根据您在查询中指定的条件匹配两个表,并且仅返回匹配的行。如果联接中第一个表中的行与第二个表中的两行匹配,则结果中将返回两行。如果第一个表中的行与第二个表中的行不匹配,则不会返回该行;同样,如果第二个表中的行与第一个表中的行不匹配,则不会返回该行。

外部连接。

左联接尝试查找第一个表中的行与第二个表中的行的匹配项。如果找不到匹配项,它将返回第一个表中的列,并将第二个表中的列留空 (null)。

953赞 Martin Smith 12/13/2014 #10

维恩图并不能真正为我做到这一点。

例如,它们没有显示交叉连接和内部连接之间的任何区别,或者更一般地显示不同类型的连接谓词之间的任何区别,或者提供一个框架来推理它们将如何操作。

理解逻辑处理是无可替代的,无论如何,它相对容易掌握。

  1. 想象一个交叉连接。
  2. 针对步骤 1 中的所有行计算子句,将谓词计算为ontrue
  3. (仅适用于外部联接)重新添加在步骤 2 中丢失的任何外部行。

(注意:在实践中,查询优化器可能会找到比上述纯逻辑描述更有效的查询执行方法,但最终结果必须相同)

我将从一个完整的外部连接的动画版本开始。进一步的解释如下。

enter image description here


解释

源表

enter link description here

首先从一个(又名笛卡尔积)开始。它没有子句,只是返回两个表中的每个行组合。CROSS JOINON

从交叉连接 B 中选择 A.Colour、B.Colour

enter link description here

内部连接和外部连接具有“ON”子句谓词。

  • 内部连接。计算交叉联接结果中所有行的“ON”子句中的条件。如果为 true,则返回联接行。否则丢弃它。
  • 左外连接。与内部联接相同,然后对于左表中与任何内容不匹配的任何行,输出这些行,右表列的 NULL 值为空。
  • 右外连接。与内部联接相同,然后对于右表中与任何内容不匹配的任何行,输出这些行,左表列的 NULL 值。
  • 完全外部连接。与内部连接相同,然后保留左外连接中的左不匹配行,并保留右外连接中的右不匹配行。

一些例子

SELECT A.Colour, B.Colour FROM A INNER JOIN B ON A.Colour = B.Colour

以上是经典的 equi join。

Inner Join

动画版

enter image description here

选择 A.Colour, B.Colour FROM A INNER JOIN B ON A.Colour NOT IN ('Green', 'Blue')

内部联接条件不一定是相等条件,也不需要引用两个表(甚至两个表之一)中的列。对交叉联接的每一行进行计算将返回。A.Colour NOT IN ('Green','Blue')

inner 2

选择 A.Colour, B.Colour FROM A INNER JOIN B ON 1 =1

对于交叉联接结果中的所有行,联接条件的计算结果为 true,因此这与交叉联接相同。我不会再重复 16 行的图片了。

选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour

外部联接的逻辑计算方式与内部联接相同,不同之处在于,如果左表中的一行(对于左联接)根本没有与右表中的任何行联接,则该行将保留在结果中,并保留右侧列的值。NULL

LOJ

选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour IS NULL

这只会将上一个结果限制为仅返回其中 .在这种特殊情况下,这些将是保留的行,因为它们在右侧表中没有匹配项,并且查询返回表中不匹配的单个红色行。这被称为反半挂接。B.Colour IS NULLB

请务必为测试选择一个不可为 null 的列,或者联接条件确保排除任何值的列,以便此模式正常工作,并避免只带回恰好具有该列值的行以及不匹配的行。IS NULLNULLNULL

loj is null

选择 A.Colour, B.Colour FROM A RIGHT OUTER JOIN B ON A.Colour = B.Colour

右外联接的作用与左外联接类似,只是它们保留右表中的不匹配行,而 null 扩展左列。

ROJ

选择 A.Colour, B.Colour FROM A FULL OUTER JOIN B ON A.Colour = B.Colour

完全外部连接结合了左连接和右连接的行为,并保留了左表和右表中的不匹配行。

FOJ

选择 A.Colour, B.Colour FROM A FULL OUTER JOIN B ON 1 = 0

交叉联接中没有与谓词匹配的行。两端的所有行都使用常规的外部联接规则进行保留,另一端表中的列中为 NULL。1=0

FOJ 2

选择 COALESCE(A.Colour, B.Colour) 作为颜色 从完全外部连接 B 上 1 = 0

通过对前面的查询进行小幅修改,可以模拟两个表中的一个。UNION ALL

UNION ALL

选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour = 'Green'

请注意,该子句(如果存在)在逻辑上在联接后运行。一个常见的错误是执行左外联接,然后在右表上包含一个 WHERE 子句,该子句带有条件,最终排除不匹配的行。以上内容最终执行了外部连接...WHERE

LOJ

...然后运行“Where”子句。 计算结果不为 true,因此外部连接保留的行最终被丢弃(与蓝色连接一起),有效地将连接转换回内部连接。NULL= 'Green'

LOJtoInner

如果意图仅包括 B 中颜色为绿色的行和 A 中的所有行,则无论正确的语法为

选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour AND B.Colour = 'Green'

enter image description here

SQL 小提琴

请参阅这些在 SQLFiddle.com 上实时运行的示例。

评论

68赞 Old Pro 12/20/2014
我要说的是,虽然这对我来说不如维恩图那么有效,但我很欣赏人们的变化和学习方式不同,这是一个非常好的解释,与我以前见过的任何解释都不同,所以我支持@ypercube奖励积分。也很好地解释了在 JOIN 子句和 WHERE 子句中放置附加条件的区别。向你致敬,马丁·史密斯。
32赞 Martin Smith 12/20/2014
@OldPro 维恩图就目前而言,我想是可以的,但它们对如何表示交叉连接或区分一种连接谓词(例如等值连接)与另一种连接谓词保持沉默。在交叉连接结果的每一行上评估连接谓词,然后在不匹配的行中添加回去(如果是外部连接),最后评估 where 对我来说效果更好的心智模型。
23赞 ypercubeᵀᴹ 12/21/2014
维恩图适用于表示并集、交集和差异,但不能表示连接。对于非常简单的连接,它们有一些次要的教育价值,即连接条件位于唯一列上的连接。
17赞 Martin Smith 1/28/2016
@Arth - 不,你错了。SQL Fiddle sqlfiddle.com/#!3/9eecb7db59d16c80417c72d1/5155 这是维恩图无法说明的。
8赞 Git Gud 5/24/2018
你是怎么做这些动画的?很好的答案,我唯一不喜欢的是你谦虚地说维恩图不适合你。现实情况是,它们不足以模拟正在发生的事情,这一点很重要,以免人们产生错误的想法。
250赞 ajitksharma 12/18/2014 #11

联接用于合并两个表中的数据,结果是一个新的临时表。联接是基于称为谓词的东西执行的,谓词指定执行联接时要使用的条件。内部联接和外部联接之间的区别在于,内部联接将仅返回基于联接谓词实际匹配的行。 例如,让我们考虑 Employee 和 Location 表:

员工

EmpID EmpName(英语:EmpName)
13 杰森
8 亚历克斯
3 公羊
17 先生
25 约翰生

位置

EmpID EmpLoc (英语)
13 圣何塞
8 洛杉矶
3 印度浦那
17 Chennai, 印度
39 印度班加罗尔

内部连接:-内部联接通过基于联接谓词组合两个表(EmployeeLocation)的列值来创建新的结果表。该查询将 Employee 的每一行与 Location 的每一行进行比较,以查找满足联接谓词的所有行对。当通过匹配非 NULL 值来满足联接谓词时,EmployeeLocation 的每对匹配行的列值将合并到结果行中。 下面是内部联接的 SQL 的样子:

select  * from employee inner join location on employee.empID = location.empID
OR
select  * from employee, location where employee.empID = location.empID

现在,运行该 SQL 的结果如下所示:

Employee.EmpId Employee.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 公羊 3 印度浦那
17 先生 17 Chennai, 印度

外接头:-外部联接不要求两个联接表中的每条记录都具有匹配的记录。联接表将保留每条记录,即使不存在其他匹配记录也是如此。外联接进一步细分为左外联接和右外联接,具体取决于保留的表行(左行或右行)。

左外连接:-表 Employee 和 Location 的左外联接(或简称为左联接)的结果始终包含“左”表 (Employee) 的所有记录,即使联接条件在“右”表 (Location) 中找不到任何匹配的记录也是如此。 下面是左外联接的 SQL 的样子,使用上表:

select  * from employee left outer join location on employee.empID = location.empID;
//Use of outer keyword is optional

现在,运行此 SQL 的结果如下所示:

Employee.EmpId Employee.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 公羊 3 印度浦那
17 先生 17 Chennai, 印度
25 约翰生

请注意,虽然 Johnson 在员工位置表中没有条目,但他仍包含在结果中,但位置字段为空。

右外连接:-右外连接(或右连接)与左外连接非常相似,只是表的处理方式相反。“右”表(位置)中的每一行都将在联接表中至少出现一次。如果“左”表 (Employee) 中不存在匹配的行,则 NULL 将显示在 Employee 的列中,用于在 Location 中没有匹配的记录。 这是 SQL 的样子:

select * from employee right outer join location  on employee.empID = location.empID;
//Use of outer keyword is optional

使用上面的表格,我们可以显示右外连接的结果集是什么样子的:

Employee.EmpId Employee.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 公羊 3 印度浦那
17 先生 17 Chennai, 印度
39 印度班加罗尔

请注意,虽然没有员工被列为在班加罗尔工作,但它仍然包含在结果中,而员工字段被清空。

全外联结:-完全外部连接或完全连接是通过在连接结果中包含不匹配的行来保留不匹配的信息,使用完全外部连接。它包括两个表中的所有行,而不管另一个表是否具有匹配的值。

Employee.EmpId Employee.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 公羊 3 印度浦那
17 先生 17 Chennai, 印度
25 约翰生
39 印度班加罗尔

MySQL 8.0 参考手册 - 连接语法

Oracle Join 操作

评论

1赞 philipxy 11/6/2019
维恩图被错误地标记了。请参阅我对问题和其他答案的评论。此外,这种语言中的大多数都很差。例如:“当通过匹配非 NULL 值来满足联接谓词时,Employee 和 Location 的每对匹配行的列值将合并到结果行中。否,而不是“当通过匹配非 NULL 值来满足连接谓词时”。行中的值无关紧要,重要的是整个条件是真还是假。对于真实条件,某些值很可能是 NULL。
0赞 philipxy 11/26/2021
@Persistence 表格需要的是表格初始化代码的文本,这些代码以适合复制、粘贴和运行的列格式化。
84赞 Pratik Joshi 2/19/2015 #12

简单来说:

内部联接 -> 仅从父表和子表中获取公共记录,其中父表的主键与子表中的外键匹配。

左联接 ->

伪代码

1.Take All records from left Table
2.for(each record in right table,) {
    if(Records from left & right table matching on primary & foreign key){
       use their values as it is as result of join at the right side for 2nd table.
    } else {
       put value NULL values in that particular record as result of join at the right side for 2nd table.
    }
  }

右连接:与左连接正好相反。将表名放在右侧的 LEFT JOIN 中,您将获得与 LEFT JOIN 相同的输出。

外部连接:显示两个表中的所有记录。如果左表中的记录与基于主键的右表不匹配,则使用空值作为连接的结果。No matter what

例:

Example

现在让我们假设 2 张桌子

1.employees , 2.phone_numbers_employees

employees : id , name 

phone_numbers_employees : id , phone_num , emp_id   

这里,employees 表是 Master 表,phone_numbers_employees 是子表(它包含连接其子表的外键。emp_idemployee.id

内部连接

仅当员工表(其 id)的主键与子表phone_numbers_employees(emp_id)的外键匹配时,才记录 2 个表。

所以查询将是:

SELECT e.id , e.name , p.phone_num FROM employees AS e INNER JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

如上所述,这里仅取主键 = 外键上的匹配行。在这里,主键 = 外键上的不匹配行作为连接的结果被跳过。

左连接

左联接将保留左表的所有行,而不管右表上是否有匹配的行。

SELECT e.id , e.name , p.phone_num FROM employees AS e LEFT JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

外部连接

SELECT e.id , e.name , p.phone_num FROM employees AS e OUTER JOIN phone_numbers_employees AS p ON e.id = p.emp_id;

从图解上看,它看起来像:

Diagram

评论

5赞 philipxy 8/10/2015
结果与主键/唯一键/候选键和外键无关(本身)。救世主可以而且应该在不提及它们的情况下进行描述。计算交叉连接,然后过滤掉与 ON 条件不匹配的行;此外,对于外部联接,过滤/不匹配的行由 NULL 扩展(根据 LEFT/RIGHT/FULL 并包含。
1赞 Colm Bhandal 5/8/2020
SQL联接在主键/外键上始终匹配的假设导致了维恩图的滥用。请相应地修改您的答案。
55赞 shA.t 4/13/2015 #13

答案在于每一个的含义,所以在结果中。

注意:
中没有或。
而且没有.
SQLiteRIGHT OUTER JOINFULL OUTER JOINMySQLFULL OUTER JOIN

我的回答基于上面的注释

当您有两个像这样的表时:

--[table1]               --[table2]
id | name                id | name
---+-------              ---+-------
1  | a1                  1  | a2
2  | b1                  3  | b2

交叉连接/外部连接:您可以像这样拥有所有这些表数据,也可以像这样使用:
CROSS JOIN,

SELECT * FROM table1, table2
--[OR]
SELECT * FROM table1 CROSS JOIN table2

--[Results:]
id | name | id | name 
---+------+----+------
1  | a1   | 1  | a2
1  | a1   | 3  | b2
2  | b1   | 1  | a2
2  | b1   | 3  | b2

内部连接 :当您想根据关系向上述结果添加过滤器时,您可以使用:
table1.id = table2.idINNER JOIN

SELECT * FROM table1, table2 WHERE table1.id = table2.id
--[OR]
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id

--[Results:]
id | name | id | name 
---+------+----+------
1  | a1   | 1  | a2

LEFT [OUTER] JOIN :
当您想在上述结果中拥有其中一个表的所有行时 - 具有相同的关系 - 您可以使用:
(对于RIGHT JOIN,只需更改表的位置)
LEFT JOIN

SELECT * FROM table1, table2 WHERE table1.id = table2.id 
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
--[OR]
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id

--[Results:]
id | name | id   | name 
---+------+------+------
1  | a1   | 1    | a2
2  | b1   | Null | Null

FULL OUTER JOIN :
当您还希望在结果中包含其他表的所有行时,可以使用:
FULL OUTER JOIN

SELECT * FROM table1, table2 WHERE table1.id = table2.id
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
UNION ALL
SELECT Null, Null, * FROM table2 WHERE Not table2.id In (SELECT id FROM table1)
--[OR] (recommended for SQLite)
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
UNION ALL
SELECT * FROM table2 LEFT JOIN table1 ON table2.id = table1.id
WHERE table1.id IS NULL
--[OR]
SELECT * FROM table1 FULL OUTER JOIN table2 On table1.id = table2.id

--[Results:]
id   | name | id   | name 
-----+------+------+------
1    | a1   | 1    | a2
2    | b1   | Null | Null
Null | Null | 3    | b2

好吧,根据您的需要,您可以选择满足您需求;)的每一个。

33赞 onedaywhen 1/22/2016 #14

在批评了备受喜爱的红色阴影维恩图之后,我认为发布我自己的尝试是公平的。

尽管 @Martin Smith 的答案是这群人中最好的,但他只显示了每个表中的键列,而我认为理想情况下也应该显示非键列。

在允许的半小时内,我能做的最好的事情是,我仍然认为它没有充分表明由于缺少键值而存在空值,或者这实际上是联合而不是连接:TableBOUTER JOIN

enter image description here

评论

2赞 LearnByReading 1/23/2016
问题是问 INNER 和 OUTER 连接之间的区别,但不一定是留下外部连接
0赞 onedaywhen 4/29/2019
@LearnByReading:我右边的图片是一个右外连接,即替换为TableA a LEFT OUTER JOIN TableB bTableB B RIGHT OUTER JOIN TableA a
3赞 Sandesh 2/2/2016 #15
  • 内部联接 - 使用任一等效查询的内部联接给出两个的交集,即它们共有的两行。

  • 左外联接 - 左外联接将给出 A 中的所有行,以及 B 中的任何公共行。

  • 完全外连接 - 完全外部连接将为您提供 A 和 B 的并集,即 A 中的所有行和 B 中的所有行。如果 A 中的某些东西在 B 中没有相应的基准面,则 B 部分为 null,反之亦然

评论

2赞 philipxy 2/3/2017
这既是错误的,也是不清楚的。除非表具有相同的列,否则联接不是交集。外部联接没有来自 A 或 B 的行,除非它们具有相同的列,在这种情况下,不会添加 null。你试图说些什么,但你没有说出来。你没有正确或清楚地解释。
0赞 SuicideSheep 4/11/2017
@philipxy:不同意你的说法。您可以联接所需的任何列,如果值匹配,它们将联接在一起。Join is not an intersection unless the tables have the same columns
1赞 philipxy 4/11/2017
该评论和您的答案一样不清楚。(我想你可能会这样想,结果的公共列的子行值集是每个输入的公共列的子行值集的交集;但这不是你写的。你不清楚。
1赞 philipxy 2/5/2020
我的意思是,当连接是具有相同列的输入的自然内部连接时,它只是输入的交集。你错误地使用了“交叉”和“联合”这两个词。
25赞 Akshay Khale 4/28/2016 #16

最简单的定义

内部联接:从两个表中返回匹配的记录

完全外部联接:返回两个表中的匹配和不匹配的记录,两个表中的不匹配记录为 null。

左外联接:仅从左侧表中返回匹配和不匹配的记录。

右外联接:仅从右侧的表中返回匹配和不匹配的记录。

简而言之

匹配 + 左不匹配 + 右不匹配 = 完全外部连接

匹配 + 左不匹配 = 左外连接

匹配 + 右不匹配 = 右外连接

匹配 = 内部联接

评论

1赞 yeliabsalohcin 9/5/2017
这太棒了,并解释了为什么 join 不能按预期工作时间序列索引。相隔一秒的时间戳是无与伦比的。
1赞 philipxy 11/22/2017
@yeliabsalohcin 您没有在这里解释“按预期”或在对问题的评论中“有效”。这只是一些无法解释的个人误解,你奇怪地期望别人有。如果你在阅读时草率地对待文字——误解清晰的写作和/或接受不清晰的写作——就像你在这里写作时一样,那么你可能会有误解。事实上,这个答案和这里的大多数答案一样,是不清楚和错误的。当输入列集不同时,“内部联接:从两个表返回匹配的记录”是错误的。它试图说某种东西,但事实并非如此。(见我的回答。
14赞 Anands23 10/13/2016 #17

简单来说,

1.INNER JOIN OR EQUI JOIN :返回仅与两个表中的条件匹配的结果集。

2.OUTER JOIN :返回两个表中所有值的结果集,即使条件是否匹配。

3.LEFT JOIN:返回左表中所有值的结果集,仅返回与右表中的条件匹配的行的结果集。

4.RIGHT JOIN:返回右表中所有值的结果集,仅返回与左表中的条件匹配的行。

5.FULL JOIN:Full Join和Full outer Join相同。

33赞 S.Serpooshan 11/8/2016 #18

的精确算法如下:INNER JOINLEFT/RIGHT OUTER JOIN

  1. 从第一个表中获取每一行:a
  2. 考虑它旁边的第二个表中的所有行:(a, b[i])
  3. 针对每对评估子句:ON ...ON( a, b[i] ) = true/false?
    • 当条件的计算结果为 时,返回组合行。true(a, b[i])
    • 当到达第二个表的末尾而没有任何匹配时,这是一个(虚拟)对,用于其他表的所有列:用于 LEFT 外连接或用于 RIGHT 外部连接。这是为了确保第一个表的所有行都存在于最终结果中。Outer JoinNull(a, Null)(Null, b)

注意:子句中指定的条件可以是任何内容,不需要使用主键(并且您不需要总是引用两个表中的列)!例如:ON

  • ... ON T1.title = T2.title AND T1.version < T2.version( => 将这篇文章视为示例用法:仅选择列上具有最大值的行)
  • ... ON T1.y IS NULL
  • ... ON 1 = 0(仅作为示例)

Inner Join vs. Left Outer Join


enter image description here

注意:左连接 = 左外连接,右连接 = 右外连接。

评论

0赞 wenn32 9/7/2023
“ON T1.col1 = T2.col2 + 1”的匹配如何工作?两列之间实际匹配的是什么?
4赞 Laxmi 7/10/2017 #19

1.Inner Join:也称为Join。仅当存在匹配项时,它才会返回左表和右表中存在的行。否则,它将返回零条记录。

例:

SELECT
  e1.emp_name,
  e2.emp_salary    
FROM emp1 e1
INNER JOIN emp2 e2
  ON e1.emp_id = e2.emp_id

output1

2.全外联接:又称全联接。它返回左表和右表中存在的所有行

例:

SELECT
  e1.emp_name,
  e2.emp_salary    
FROM emp1 e1
FULL OUTER JOIN emp2 e2
  ON e1.emp_id = e2.emp_id

output2

3.左外连接:或简称为左连接。它返回左表中存在的所有行以及右表中的匹配行(如果有)。

4.右外连接:也称为右连接。它返回左表中的匹配行(如果有),以及右表中存在的所有行。

joins

联接的优点

  1. 执行速度更快。
10赞 philipxy 9/7/2017 #20

left join on返回 Rows 与 S 扩展的左侧表行不匹配。inner join onunion allnull

right join on返回行 不匹配的右表行扩展了 s。inner join onunion allnull

full join on返回行 不匹配的左表行 扩展 S 不匹配的右表行 扩展 S 的行。inner join onunion allnullunion allnull

outer是可选的,没有效果。

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

因此,在您知道涉及什么底层之前,不要这样做。outer join oninner join on


找出返回的行:SQL 中的 CROSS JOIN 与 INNER JOINinner join on

这也解释了为什么维恩图对内部连接与外部连接没有帮助。 有关为什么它们通常对连接没有帮助的更多信息:自然连接的维恩图

评论

0赞 onedaywhen 4/25/2019
我确实阅读了您的许多评论。当你说,“维恩图,如果解释得当,可以表示内部与外部连接”,你的意思是当观察者或维恩图本身正确解释时?如果是后者,请画:)
1赞 philipxy 4/25/2019
我不确定你想说什么。我说的是维恩图作为元素集的标准解释。(因为图表的某些用法甚至无法做到这一点。对于应用程序来说,“正确”包括说明集合和/或元素是什么。请参阅本页顶部的评论,其中包含 50 个赞成票,用于内部与外部连接的维恩图。我会把我的一些评论编辑到这个问题中。我不想在这篇文章中使用维恩图。
0赞 philipxy 4/26/2019
我必须承认,尽管我在评论中措辞很快,但由于 SQL 涉及 bags 和 null,并且 SQL 文化没有通用术语来命名和区分相关概念,即使清楚地解释维恩图的元素如何与输出“行”是 1:1 的,更不用说输入“行”了,这也不是平凡的。或者内部或外部连接的作用,更不用说它们的区别了。“value”可能包含也可能不包含 NULL,“row”可能是值列表与表值或变量中的插槽 & “=” 可能是 SQL“=”与相等。
0赞 onedaywhen 4/29/2019
与我们的笛卡尔乘积与关系乘积的讨论类似,我怀疑维恩图对于已经了解连接类型之间差异的人来说很有意义!
0赞 philipxy 4/29/2019
在“关系笛卡尔乘积”的情况下,它是人们普遍理解的某种事物的标准和合理名称,并且被合理地描述为与笛卡尔乘积相似。在 SQL 维恩图的情况下,它们没有意义,人们只是假设他们有,无论他们是否理解运算符/差异。
3赞 rashedcs 10/17/2017 #21

和的区别如下:inner joinouter join

  1. Inner join是基于匹配元组组合表的联接,而是基于匹配和不匹配元组组合表的联接。outer join
  2. Inner join合并两个表中的匹配行,其中省略了不匹配的行,而合并两个表中的行和不匹配的行填充 null 值。outer join
  3. Inner join类似于交叉操作,而类似于联合操作。outer join
  4. Inner join是两种类型,而是三种类型。outer join
  5. outer join比 快。inner join

评论

2赞 Martin Smith 1/9/2020
外部连接结果与内部连接相同,但增加了一些额外的行,所以我不知道为什么您认为外部连接会更快。另外,这“两种类型”的内部连接是什么?我想你指的是外层的全、左和右?
1赞 philipxy 1/9/2020
外部连接不比内部连接快。
37赞 Premraj 12/27/2017 #22

enter image description here

  • INNER JOIN两个或多个表的最典型联接。 它返回表 ON 主键和 forignkey 关系的数据匹配。
  • OUTER JOIN与 相同,但它也包括 ResultSet 上的数据。INNER JOINNULL
    • LEFT JOIN = INNER JOIN+ 表的数据与右表的匹配数据不匹配。Null
    • RIGHT JOIN = INNER JOIN+ 表的数据与左表的匹配数据不匹配。Null
    • FULL JOIN = INNER JOIN+ 左右表的匹配数据不匹配。Null
  • 自连接在 SQL 中不是一个关键字,当表引用数据时,它本身称为自连接。使用 和 我们可以编写自连接查询。INNER JOINOUTER JOIN

例如:

SELECT * 
FROM   tablea a 
       INNER JOIN tableb b 
               ON a.primary_key = b.foreign_key 
       INNER JOIN tablec c 
               ON b.primary_key = c.foreign_key 
4赞 Mayank Porwal 11/25/2018 #23

请考虑以下 2 个表:

DM1型

empid   name    dept_id salary
1       Rob     1       100
2       Mark    1       300
3       John    2       100
4       Mary    2       300
5       Bill    3       700
6       Jose    6       400

部门

deptid  name
1       IT
2       Accounts
3       Security
4       HR
5       R&D

内部连接:

在sql查询中,大多只写成JOIN。它仅返回表之间的匹配记录。

找出所有员工及其部门名称:

Select a.empid, a.name, b.name as dept_name
FROM emp a
JOIN department b
ON a.dept_id = b.deptid
;

empid   name    dept_name
1       Rob     IT
2       Mark    IT
3       John    Accounts
4       Mary    Accounts
5       Bill    Security

如上所述,不是从输出中的 EMP 打印的,因为它dept_id在 Department 表中找不到匹配项。同样,和行不会从 Department 表打印,因为它们在 Emp 表中找不到匹配项。Jose6HRR&D

因此,INNER JOIN 或仅返回 JOIN 仅返回匹配的行。

左加入 :

这将返回 LEFT 表中的所有记录,并且仅返回 RIGHT 表中的匹配记录。

Select a.empid, a.name, b.name as dept_name
FROM emp a
LEFT JOIN department b
ON a.dept_id = b.deptid
;

empid   name    dept_name
1       Rob     IT
2       Mark    IT
3       John    Accounts
4       Mary    Accounts
5       Bill    Security
6       Jose    

因此,如果您观察上述输出,则 LEFT 表(Emp) 中的所有记录都仅打印 RIGHT 表中的匹配记录。

HR并且行不是从 Department 表打印的,因为它们在 dept_id 的 Emp 表中找不到匹配项。R&D

因此,LEFT JOIN 返回 Left 表中的所有行,并且仅返回 RIGHT 表中的匹配行。

也可以在这里查看演示。

4赞 ForguesR 10/26/2019 #24

这里有很多很好的答案,有非常准确的关系代数示例。这是一个非常简化的答案,可能对有 SQL 编码困境的业余或新手编码人员有所帮助。

基本上,查询通常归结为两种情况:JOIN

对于数据子集:SELECTA

  • 当您要查找的相关数据必须根据数据库设计存在时使用;INNER JOINB
  • 根据数据库设计,当您要查找的相关数据可能存在或可能不存在时使用。LEFT JOINB
32赞 Scratte 5/7/2020 #25

总体思路

请参阅 Martin Smith回答,以更好地说明和解释不同的连接,包括 和 之间的差异。FULL OUTER JOINRIGHT OUTER JOINLEFT OUTER JOIN

这两个表构成了以下表示的基础:JOIN

Basis

交叉连接

CrossJoin

SELECT *
  FROM citizen
 CROSS JOIN postalcode

结果将是所有组合的笛卡尔积。无需任何条件:JOIN

CrossJoinResult

内部连接

INNER JOIN就是简单地说:JOIN

InnerJoin

SELECT *
  FROM citizen    c
  JOIN postalcode p ON c.postal = p.postal

结果将是满足所需条件的组合:JOIN

InnerJoinResult

左外连接

LEFT OUTER JOINLEFT JOIN

LeftJoin

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON c.postal = p.postal

结果将是 一切 即使 中没有匹配项。同样,需要一个条件:citizenpostalcodeJOIN

LeftJoinResult

播放数据

所有示例均已在 Oracle 18c 上运行。它们可以在 dbfiddle.uk 上找到,这也是表格屏幕截图的来源。

CREATE TABLE citizen (id      NUMBER,
                      name    VARCHAR2(20),
                      postal  NUMBER,  -- <-- could do with a redesign to postalcode.id instead.
                      leader  NUMBER);

CREATE TABLE postalcode (id      NUMBER,
                         postal  NUMBER,
                         city    VARCHAR2(20),
                         area    VARCHAR2(20));

INSERT INTO citizen (id, name, postal, leader)
              SELECT 1, 'Smith', 2200,  null FROM DUAL
        UNION SELECT 2, 'Green', 31006, 1    FROM DUAL
        UNION SELECT 3, 'Jensen', 623,  1    FROM DUAL;

INSERT INTO postalcode (id, postal, city, area)
                 SELECT 1, 2200,     'BigCity',         'Geancy'  FROM DUAL
           UNION SELECT 2, 31006,    'SmallTown',       'Snizkim' FROM DUAL
           UNION SELECT 3, 31006,    'Settlement',      'Moon'    FROM DUAL  -- <-- Uuh-uhh.
           UNION SELECT 4, 78567390, 'LookoutTowerX89', 'Space'   FROM DUAL;

玩 和 时边界模糊JOINWHERE

交叉连接

CROSS JOIN导致行作为 The General Idea/:INNER JOIN

SELECT *
  FROM citizen          c
  CROSS JOIN postalcode p
 WHERE c.postal = p.postal -- < -- The WHERE condition is limiting the resulting rows

用于获取 a 的结果需要一些技巧,例如在行中添加。它被省略了。CROSS JOINLEFT OUTER JOINNULL

内部连接

INNER JOIN成为笛卡尔乘积。这与 The General Idea/:CROSS JOIN

SELECT *
  FROM citizen    c
  JOIN postalcode p ON 1 = 1  -- < -- The ON condition makes it a CROSS JOIN

在这里,内部连接可以真正看作是结果与删除的条件不匹配的交叉连接。此处不会删除任何生成的行。

用于获得 a 的结果也需要技巧。它被省略了。INNER JOINLEFT OUTER JOIN

左外连接

LEFT JOIN结果在行中作为 The General Idea/:CROSS JOIN

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON 1 = 1 -- < -- The ON condition makes it a CROSS JOIN

LEFT JOIN结果在行中作为 The General Idea/:INNER JOIN

SELECT *
  FROM citizen         c
  LEFT JOIN postalcode p ON c.postal = p.postal
 WHERE p.postal IS NOT NULL -- < -- removed the row where there's no mathcing result from postalcode

维恩图的麻烦

在互联网上搜索“sql join cross inner outer”的图像将显示大量维恩图。我的办公桌上曾经有一份打印本。但是表示存在问题。

维恩图非常适合集合论,其中元素可以在一个或两个集合中。但是对于数据库来说,在我看来,一个“集合”中的元素似乎是表中的一行,因此在任何其他表中都不存在。多个表中没有一行这样的事情。行对于表是唯一的。

自连接是一种极端情况,其中每个元素在两个集合中实际上是相同的。但它仍然没有以下任何问题。

在下面的讨论中,集合代表左边(桌子)上的集合,集合是右边(桌子)上的集合。AcitizenBpostalcode

交叉连接

两个集合中的每个元素都与另一个集合中的每个元素匹配,这意味着我们需要每个元素的数量和每个元素的数量来正确表示这个笛卡尔乘积。集合论不是为集合中的多个相同元素制作的,因此我发现维恩图无法正确表示它是不切实际/不可能的。这似乎根本不合适。ABBAUNION

行是不同的。总共有 7 行。但它们与通用结果集不兼容。这根本不是 a 的工作方式:UNIONSQLCROSS JOIN

CrossJoinUnion1

试图像这样表示它:

CrossJoinUnion2Crossing

..但现在它看起来只是一个,当然不是。此外,实际上在两个不同的集合中的任何一个中都没有元素。但是,它看起来非常类似于类似于以下内容的可搜索结果:INTERSECTIONINTERSECTION

CrossJoinUnionUnion3

作为参考,可以在 Tutorialgateway 上看到一个可搜索的 s 结果。就像这个一样,是空的。CROSS JOININTERSECTION

内部连接

元素的值取决于条件。在每一行对于该条件都是唯一的条件下,可以表示这一点。含义仅适用于行。一旦表()中的一行与表()中的多行匹配,结果就会出现与以下相同的问题: 该行需要多次表示,而集合论并不是真正为此而制定的。在唯一性的条件下,该图可以工作,但请记住,该条件决定了图中元素的位置。只看条件的值,而行的其余部分只是在骑行中:JOINid=xAcitizenBpostalcodeJOINCROSS JOINJOINJOIN

InnerJoinIntersection - Filled

当使用 a with a 条件使其变成 .INNER JOINON 1 = 1CROSS JOIN

使用 self- 时,行实际上是两个表中的标识元素,但将表表示为两者并不是很合适。例如,使 中的元素与 B 中的不同元素匹配的常见自条件是 ,使匹配从到到在单独的元素上。从这样的示例来看:JOINABJOINAON A.parent = B.childABSQL

SELECT *
  FROM citizen c1
  JOIN citizen c2 ON c1.id = c2.leader

SelfJoinResult

这意味着史密斯是格林和詹森的领袖。

外部连接

同样,当一行与另一个表中的行有多个匹配项时,麻烦就开始了。这更加复杂,因为 can be but of 与空集匹配。但是在集合论中,任何集合和空集合的并集总是正义的。空集不添加任何内容。这种表示通常只是显示所有 of 来说明无论是否存在匹配项,都会选择 中的行。然而,“匹配元素”存在与上图相同的问题。它们取决于条件。而空集似乎已经徘徊到:OUTER JOINCCLEFT OUTER JOINAABA

LeftJoinIntersection - Filled

WHERE 子句 - 有意义

在月球上找到带有史密斯和邮政编码的 a 中的所有行:CROSS JOIN

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
   AND p.area = 'Moon';

Where - result

现在,维恩图不用于反映 .它用于子句:JOINWHERE

Where

..这是有道理的。

当 INTERSECT 和 UNION 有意义时

相交

如前所述,an 并不是真正的 .但是,s 可用于单独查询的结果。在这里,维恩图是有意义的,因为来自单独查询的元素实际上是只属于其中一个结果或两者兼而有之的行。显然,Intersect 只会返回两个查询中都存在该行的结果。这将导致与上面的行相同的行,并且维恩图也将是相同的:INNER JOININTERSECTINTERSECTSQLWHERE

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
INTERSECT
SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE p.area = 'Moon';

联盟

an 不是 .但是,在与 相同的条件下工作,导致所有结果的返回结果结合了两个:OUTER JOINUNIONUNIONINTERSECTSELECT

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
UNION
SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE p.area = 'Moon';

这相当于:

SELECT *
  FROM citizen          c
 CROSS JOIN postalcode  p
 WHERE c.name = 'Smith'
   OR p.area = 'Moon';

..并给出结果:

Union - Result

同样在这里,维恩图是有道理的:

UNION

当它不适用时

需要注意的是,只有当两个 SELECT 的结果结构相同时,这些才有效,从而可以进行比较或合并。这两个结果将无法实现:

SELECT *
  FROM citizen
 WHERE name = 'Smith'
SELECT *
  FROM postalcode
 WHERE area = 'Moon';

..尝试将结果与给出一个UNION

ORA-01790: expression must have same datatype as corresponding expression

如需进一步的兴趣,请阅读在解释 JOIN 时对维恩图说不,并将 sql 连接作为维恩图。两者都涵盖 .EXCEPT

5赞 HUGO-DEV 7/31/2020 #26

通过一个示例更容易解释连接:

enter image description here

要模拟存储在单独表中的人员和电子邮件,

表 A 和表 B 由 Table_A.id = Table_B.name_id 连接

内部连接

enter image description here

仅显示匹配的 ID 行。

外部连接

enter image description here

将显示表 A 的匹配 ID 和不匹配的行。

enter image description here

将显示表 B 的匹配 ID 和不匹配的行。

enter image description here将显示两个表中匹配的 ID 和不匹配的行。

注意:完全外部连接在MySQL上不可用

2赞 Nathan Long 4/24/2021 #27

演示

设置

跳入并创建一个关于猫和人类的小型数据库。 您可以复制粘贴整个部分。psql

CREATE DATABASE catdb;
\c catdb;
\pset null '[NULL]' -- how to display null values

CREATE TABLE humans (
  name text primary key
);
CREATE TABLE cats (
  human_name text references humans(name),
  name text
);

INSERT INTO humans (name)
VALUES ('Abe'), ('Ann'), ('Ben'), ('Jen');

INSERT INTO cats (human_name, name)
VALUES
('Abe', 'Axel'),
(NULL, 'Bitty'),
('Jen', 'Jellybean'),
('Jen', 'Juniper');

查询

下面是一个查询,我们将运行几次,更改为各种类型以查看结果。[SOMETHING JOIN]

SELECT
humans.name AS human_name,
cats.name AS cat_name
FROM humans
[SOMETHING JOIN] cats ON humans.name = cats.human_name
ORDER BY humans.name;

An 返回所有人猫对。 任何没有猫或没有人类的猫都被排除在外。INNER JOIN

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Jen        | Jellybean
 Jen        | Juniper

A 返回所有人类和所有猫,如果两边没有匹配项。FULL OUTER JOINNULL

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Ann        | [NULL]
 Ben        | [NULL]
 Jen        | Jellybean
 Jen        | Juniper
 [NULL]     | Bitty

A 返回所有人员(左表)。 任何没有猫的人都会在列中得到一个。 任何没有人类的猫都被排除在外。LEFT OUTER JOINNULLcat_name

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Ann        | [NULL]
 Ben        | [NULL]
 Jen        | Jellybean
 Jen        | Juniper

A 返回所有猫(右表)。 任何没有人类的猫都会在列中。 任何没有猫的人都被排除在外。RIGHT OUTER JOINNULLhuman_name

 human_name | cat_name
------------+-----------
 Abe        | Axel
 Jen        | Jellybean
 Jen        | Juniper
 [NULL]     | Bitty

内部与外部

您可以看到,虽然 an 只获取匹配的对,但每种类型的联接都包含一些没有匹配项。INNER JOINOUTER

但是,实际的单词并不需要出现在查询中:INNEROUTER

  • JOIN本身意味着INNER
  • LEFT JOIN,并且都暗示RIGHT JOINOUTER JOINOUTER
1赞 Braiam 8/27/2022 #28

“外部”和“内部”只是可选元素,您只是在处理两(三)种连接。内部联接(或仅使用“联接”时的默认值)是两个表上仅存在与条件匹配的元素的联接。

“外部”联接与内部联接相同,加上左表或右表中不匹配的元素,在另一个表的所有列上添加空值。

完全连接是内部连接加上右连接和左连接。

综上所述,如果我们有这样的表 A

艾达 列表A idB的
1 1
2 莎拉 1
3 克拉克 2
4 芭比

表B是这样的:

idB的 列表B
1 康纳
2 肯特
3 斯波克

内部连接:

from tableA join tableB on tableA.idB = tableB.idB
艾达 列表A idB的 列表B
1 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特

左外连接:

from tableA left join tableB on tableA.idB = tableB.idB
艾达 列表A idB的 列表B
1 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特
4 芭比

右外连接:

from tableA right join tableB on tableA.idB = tableB.idB
艾达 列表A idB的 列表B
1 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特
3 斯波克

完全外部连接:

from tableA full join tableB on tableA.idB = tableB.idB
艾达 列表A idB的 列表B
1 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特
4 芭比
3 斯波克