关于SQL: “INNER JOIN” 和 “OUTER JOIN”?有什么区别?

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

又是怎样做的呢?

  • 在下面的答案和注释中,只有一个实际解释了维恩图如何表示运算符:圆交集区域表示联接B中的一组行。每个圆唯一的区域表示通过获取其表中不参与联接B的行并添加列而得到的一组行。其他表的唯一项都设置为空。(大多数人给A和B的圆圈提供了一个模糊的假通信。)
  • 已经提供了很多答案,但我没有看到本教程提到的内容。如果你知道维恩图,这是一个很好的教程:blog.codingsurror.com/a-visual-explanation-of-sql-joins对我来说,它足够简洁,可以快速阅读,但仍然掌握了整个概念,并且可以很好地处理所有的情况。如果你不知道维恩图是什么-学习它们。需要5-10分钟,并且在需要可视化处理集合和管理集合上的操作时会有所帮助。
  • @但丁没有,这和这里的图表有同样的问题。请看我上面的评论,再回到下面的问题,再回到那个博客帖子:"杰夫在评论中拒绝了他的博客几页"。维恩图以集合的形式显示元素。只需试着准确地确定这些图中的集合是什么以及元素是什么。集合不是表,元素不是它们的行。也可以连接任意两个表,因此pks&fks是不相关的。都是假的。你所做的正是成千上万的人所做的——得到了一个模糊的印象,你(错误地)认为这是有意义的。
  • 有人可以参考时间序列索引数据来回答这个问题吗?当涉及到时间戳时,内部和外部连接在人/维恩的意义上通常不起作用,而时间戳只相差几毫秒。
  • @Yeliabsalohcin阅读了我在这一页上的评论(和我的答案)。如果没有重复的行,那么venn图说明了外部联接和内部联接之间的区别,因此它们说明了内部联接的外部联接,反之亦然(如果您知道它们的作用)。但是,除了输入没有重复的行和相同的列之外,文氏图并没有说明外部联接或内部联接根据输入返回什么。(如果您有不同的问题,请将其作为问题发布。应用程序无关紧要。"匹配"重要,取决于数据类型和模式。)
  • 没有正式的SQL定义吗?如果是,是否不清楚?最好在问题中说明这一点,作为提出问题的动机!
  • @pjtraill本标准的定义形式为:left join on行为inner join on行,union all行不匹配,左表行扩展为空。简单。(SQL/FAST 7.7语法规则1,一般规则1 B,3 C和D,5 B)(这是我的答案中的形式,因为它是最简单的,虽然我从来没有在标准中查过,直到现在)。不幸的是标准是沉重的阅读。然而,数十本清晰的教科书和手册在网上是免费的。不幸的是,这里的答案大多是不清楚和/或混淆的。然而不幸的是,被否决了。似乎人们读得和写的一样仔细。
  • 最初的标题更清楚地说明了beng提出的问题("不同的连接类型"可以指物理连接类型,例如散列和合并)。从视图的数量来看,原始标题在搜索引擎中也很明显有效。我把不需要的编辑滚回去了


假设您连接的列没有重复项,这是非常常见的情况:

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

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

实例

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

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

请注意,(1,2)对于A是唯一的,(3,4)对于B是唯一的,(5,6)对于B是唯一的。

内连接

使用任意一个等价查询的内部联接提供两个表的交集,即它们有共同的两行。

1
2
3
4
5
6
7
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中的任何公共行。

1
2
3
4
5
6
7
8
9
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中的任何公共行。

1
2
3
4
5
6
7
8
9
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部分为空,反之亦然。

1
2
3
4
5
6
7
8
9
10
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

  • 通过在表B中添加值为4的另一行来扩充示例是很好的。这将表明内部联接不必位于相等的行数上。
  • 然而,这句话的一个很好的解释是:A和B的外部连接给出了联合B的结果,即维恩图联合的外部部分。措辞不准确。一个外部连接将给出一个Intersect B的结果,除了以下其中一个之外:所有A(左连接)、所有B(右连接)或所有A和所有B(完全连接)。只有最后一个场景才是真正的联合B。不过,这是一个写得很好的解释。
  • 很好,Mark可以用类似的方式解释MySQL性能调优。很多初学者确实需要一些简单而可靠的性能方面的解释。
  • 亲回答!喜欢它。顺便说一句:我还是找不到左连接和左外部连接等的区别。如果这不是问题的一部分,我可以发布一个新问题:)
  • 什么是b.b(+)或这只是个错误,更新版看到了类似的东西。
  • @vytautas,(+)是用于联接的ANSI SQL语法。大多数数据库都支持这两种语法。
  • 为什么每个代码示例中有两种不同的语法?
  • @timlovell-smith的(+)形式是ANSI语法。大多数数据库都支持这两种语法。
  • 完全联接是完全外部联接的别名,而左联接是左外部联接的别名,对吗?
  • 是的,非常好的解释。但是为什么在B列中,这些值不是按顺序排列的呢?也就是说,它是6.5而不是5.6?
  • @阿米尔,谢谢。join不保证订单,您需要添加一个order by子句。
  • 您的示例中可以包含自然联接吗?
  • @Markharrison也许你能帮我处理多个副本?
  • 托马斯:事实上,你和马克在措词的不同部分都是错的。"维恩图的外部部分"是指"A U B A B"。所以马克不小心直接反驳了自己,尽管他解释的其余部分显然足够清楚,足以弥补这一点。
  • 如果说外部连接是一个联合,那么当A left outer join B的结果集没有b的不匹配元素时,听起来可能有点混乱,不是吗?
  • "假设您在没有重复的列上联接,这是非常常见的情况:"-如果不是这样,会有很大的变化吗?
  • 一个连接不会给你任何东西的联合或交叉。它在格子中给你一个封闭。
  • +语法从来不是ANSI,它是Oracle,对于使用多个表或比较的表达式来说,它总是不够的。on语法是ansi。与维恩图的比较用词错误。请看我对这个问题的评论。
  • 以下是表A&B中圆/集合A&B的交叉/联合的正确声明。条件是圆A=A左连接B。圆B=(条件下的右连接B)。(条件下的完全外部联接B)=A圆联合圆B。(条件*下的内部联接B)=A圆相交圆B。圆A减去圆B=(由空扩展的联接B不匹配的行)。圆B减去圆A=(B行与扩展为空的联接B不匹配)。请看我对这个问题的评论(第一个)。
  • @不幸的是,这个解释是错误的。它的项目符号只有在所有列都相同时才正确,并且它的语言是模糊的。在你面前看到我的评论,以及我对这个问题的评论。
  • @Damian是的,外部连接和完全外部连接是等效的,同时左/右连接等同于左/右外部连接,同样的,内部连接等同于简单连接。
  • @不能将chris inner join缩短为标准SQL中的join。DBMS可能允许。MySQL确实如此。


此外,您还可以为不同的连接类型考虑以下模式;

visual explanation of joins

来源:C.L.Moffatt详细解释的SQL连接的可视化表示

  • 注意:MySQL中没有完整的外部连接。stackoverflow.com/questions/12473210/…
  • 我认为这个图假设没有重复的Key,这意味着Key是唯一的。如果Key不是唯一的,我认为结果会是一个叉,返回计数会比a的大小高得多。
  • 在排除交叉部分的完整外部联接示例中,不会使用"a.key is null"排除a中的所有行,因为如果该键为空,那么根据定义,该行不存在?我不知道这个机制是如何实现文恩图的结果的。
  • @French,请参阅我对问题的评论以及解释如何阅读维恩图的其他答案。区域不包含表A和表B中的行。它们包含通过将A中的行与B中的行配对而生成的某些行。这些行甚至不是select语句输出的行。维恩图的答案都不好。
  • A表示来自表A的所有潜在行,B表示来自表B的所有潜在行。图中的红色区域标记了哪些行将实际包含在结果集中。注意,一个表中的潜在行可能(并且经常)比该表中的实际行多。这是因为对于引用它的表B中的每一行,表A中的任何行都可能发生一次。这叫做笛卡尔积。
  • @史蒂恩德维特,这还不清楚。斜体"潜力"并没有定义它。当输入不具有相同的列时,结果集中不包含来自A或B的行,因此您的第二句话是错误的。此外,答案对图表没有任何解释,它的源代码也没有解释,它也说了关于返回行的胡说。
  • @菲利普斯,请你明白这不是我的答案。我的评论旨在帮助人们理解它。如果你能做得更好,请这样做。
  • @我知道这不是你的答案。将模糊、不完整和错误的内容添加到模糊、不完整和错误的内容中没有好处。


我推荐杰夫的博客文章。我所见过的最好的描述,加上有一个可视化,例如:

内部连接:

enter image description here

完全外部联接:

enter image description here

  • 这个图表对这个概念有点误导。阅读文章中的评论。
  • @你说的完全外部连接是什么意思?
  • 除了杰夫在评论中几页拒绝了他的博客:"评论指出,图表在多个和或重复结果的情况下分解,是绝对正确的。我实际上是在考虑沿着主键的连接,这在定义上是独特的,尽管示例并没有这样表达。像笛卡尔或叉积一样,任何导致行数超过初始值的结果都会完全破坏整个维恩图的概念。所以要记住这一点。"
  • @Philipxy是的,venn图类比只适用于忽略空值后的主键——这通常没有说明。维恩图没有帮助解释结果集中的其他列是如何用空值填充的。
  • @不幸的是,联接是否在键上(更不用说主键)并不能帮助关系图理解。(尽管我引用Jeff的话说,他认为确实如此。)(我不理解您的"忽略空值后为主键工作"或"结果集中的其他列都填充了空值"。我或多或少知道你想说的那类话,但是除了我对这个问题的评论之外,任何通信都是复杂的,所以是一个明确的解释。尽管我会欢迎的。究竟是什么被分组,如何按圈?


维恩图并不是真的适合我。好的。

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

理解逻辑处理是不可替代的,不管怎样,它都比较容易掌握。好的。

  • 想象一个交叉连接。
  • 对步骤1中的所有行评估on子句,保留谓词评估为true的行。
  • (仅用于外部联接)在步骤2中丢失的任何外部行中重新添加。
  • (注意:在实践中,查询优化程序可能会找到比上述纯逻辑描述更有效的执行查询的方法,但最终结果必须相同)好的。

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

    enter image description here好的。解释

    源表好的。

    enter link description here好的。

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

    从交叉连接中选择A.颜色,B.颜色好的。

    enter link description here好的。

    内部和外部联接有一个"on"子句谓词。好的。

    • 内部连接。为交叉联接结果中的所有行计算"on"子句中的条件。如果为真,则返回联接的行。否则丢弃它。
    • 左外联接。对于左表中不匹配任何内容的任何行,与inner join相同。使用右表列的空值输出这些内容。
    • 右外部连接。对于右表中不匹配任何内容的任何行,与内部联接相同。将这些行与左表列的空值输出。
    • 完全外部联接。与内部联接相同,然后按照左外部联接保留左不匹配行,按照右外部联接保留右不匹配行。

    一些实例

    从内部连接中选择A.颜色,B.颜色A.颜色=B.颜色好的。

    上面是典型的equi连接。好的。

    Inner Join好的。动画版本

    enter image description here好的。从内部连接中选择A.颜色,B.颜色A.颜色不在(‘绿色’、‘蓝色’)

    内部联接条件不必是相等条件,也不需要引用来自两个表(甚至其中一个表)的列。在交叉联接返回的每一行上计算A.Colour NOT IN ('Green','Blue')。好的。

    inner 2好的。

    从1=1的内部连接B中选择A.颜色,B.颜色好的。

    对于交叉联接结果中的所有行,联接条件的计算结果都为true,因此这与交叉联接相同。我不会再重复16行的图片了。好的。从左侧外部连接处选择A.颜色,B.颜色A.颜色=B.颜色

    外部联接的逻辑计算方式与内部联接相同,但如果左表中的一行(对于左联接)根本不与右表中的任何行联接,则在结果中保留右表中的NULL值。好的。

    LOJ好的。从左侧外部连接处选择A.颜色,B.颜色,A.颜色=B.颜色,其中B.颜色为空

    这只会限制前面的结果只返回B.Colour IS NULL所在的行。在这种特殊情况下,这些行将是保留的行,因为它们在右侧表中没有匹配项,查询将返回表B中不匹配的单个红色行。这就是所谓的反半连接。好的。

    IS NULL测试选择一个不可为空或联接条件确保排除任何NULL值的列是很重要的,以便此模式正确工作,并且避免只返回恰好具有该列NULL值的行以及不匹配的行。好的。

    loj is null好的。从右侧外部连接处选择A.颜色,B.颜色A.颜色=B.颜色

    右外部联接的作用类似于左外部联接,但它们保留右表中不匹配的行,空扩展左列。好的。

    ROJ好的。从一个完整的外部连接中选择A.颜色,B.颜色,A.颜色=B.颜色

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

    FOJ好的。从1=0的完整外部连接B中选择A.颜色,B.颜色

    交叉联接中没有与1=0谓词匹配的行。两边的所有行都使用正常的外部联接规则来保存,而另一边的表中的列为空。好的。

    FOJ 2好的。从1=0的完整外部连接B中选择"合并"(a.colour,b.colour)作为颜色。

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

    UNION ALL好的。从左侧外部连接B中选择A.颜色,B.颜色A.颜色=B.颜色,其中B.颜色=绿色

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

    LOJ好的。

    …然后是"where"子句。NULL= 'Green'的计算结果不是真的,因此外部联接保留的行最终会被丢弃(与蓝色联接一起),从而有效地将联接转换回内部联接。好的。

    LOJtoInner好的。

    如果只包含b中颜色为绿色的行和a中的所有行,不管正确的语法是什么好的。在A.colour=B.colour和B.colour='green'上从左侧外部连接B中选择A.colour、B.colour

    enter image description here好的。SQL小提琴

    请参阅sqlfiddle.com上运行的这些示例。好的。好啊。

    • 我要说的是,虽然这对我和维恩图都不管用,但我很欣赏人们的差异和学习方式,这是一个非常好的解释,不像我以前见过的任何解释,所以我支持@ypercube奖励积分。同时也很好地解释了在join子句和where子句中添加附加条件的区别。感谢你,马丁·史密斯。
    • @据我所知,维恩图是可以的,但是它们对于如何表示交叉连接,或者区分一种连接谓词(如equi-join)与另一种连接谓词是沉默的。在交叉联接结果的每一行上评估联接谓词,然后在外部联接的情况下添加回不匹配的行,最后评估哪一行更适合我。
    • 维恩图可以很好地表示联合、交叉和差异,但不能表示连接。对于非常简单的连接,它们具有一些较小的教育价值,即连接条件位于唯一列上的连接。
    • 在不使用distinct的情况下,有没有办法得到a的两个绿色行和一个蓝色行?
    • @LUK2302-是的,您需要半连接。不过,在SQL中没有半联接关键字。相反,您可以使用inexists。即SELECT A.Colour FROM A WHERE A.Colour IN (SELECT B.Colour FROM B)SELECT A.Colour FROM A WHERE EXISTS (SELECT * FROM B WHERE A.Colour = B.Colour)
    • 谢谢,我已经使用了where exists,而且它可以工作。但我希望有一种方法可以实现这一点,只要定期加入。不管怎样,还是谢谢你!顺便说一句:连接的表示要比用维恩图好得多。)
    • 很肯定,许多联接结果的绿行太多。例如,第一个内部联接应该只有两个绿色行。实际上,几乎所有连续有4个绿色行的情况都应该只有2行。
    • @阿尔斯-不,你错了。sql fiddle sqlpiddle.com/!3/9EECB7DB59D16C80417C72D1/5155这是维恩图无法说明的。
    • @马丁史密斯哇,我同意,我完全错了!太习惯和一个人一起工作了。谢谢你的纠正。
    • 不幸的是,在一般情况下,您的插图并不能说明左连接与内部连接。尽管这里的大多数维恩图也仅限于说明特殊情况,但如果正确解释,维恩图可以表示内部连接和外部连接,交叉点保持绿色的内部连接行。看看我的其他评论。
    • 我在sqlfiddle.com上重新创建了这些优秀的示例,供任何人尝试运行。取消对任何要运行的查询的注释。
    • 你是怎么做这些动画的?很好的答案,我唯一不喜欢的是你谦虚地说文氏图解不适合你。事实是,他们不足以模拟正在发生的事情,这一点很重要,以免人们得到错误的想法。
    • @吉特古德,我会质疑维恩图,虽然不完整,为我补充这个答案。就像前面所说的,人们有不同的学习方式。
    • @使用维恩图得出的答案不清楚、不完整和错误,包括使用维恩图。请参阅我在本页其他地方对该问题的第一条评论。容忍这种写作不是一种学习方式。这显然是一种写作风格。以及(从upvotes&comments)阅读风格。


    联接用于组合来自两个表的数据,其结果是一个新的临时表。连接是基于一个叫做谓词的东西来执行的,它指定了执行连接时要使用的条件。内部联接和外部联接的区别在于,内部联接只返回基于联接谓词实际匹配的行。让我们考虑雇员和位置表:

    enter image description here

    内部连接:内部联接通过基于联接谓词组合两个表(雇员和位置)的列值来创建新的结果表。查询将雇员的每一行与位置的每一行进行比较,以查找满足联接谓词的所有行对。当通过匹配非空值来满足联接谓词时,Employee和Location的每对匹配行的列值都被合并到结果行中。内部联接的SQL如下所示:

    1
    2
    3
    SELECT  * FROM employee INNER JOIN location ON employee.empID = location.empID
    OR
    SELECT  * FROM employee, location WHERE employee.empID = location.empID

    下面是运行该SQL的结果:enter image description hereenter image description here

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

    左外部连接:表employee和location的左外部联接(或简单的左联接)的结果始终包含"左"表(employee)的所有记录,即使联接条件在"右"表(location)中找不到任何匹配的记录。下面是左外部联接的SQL,使用上面的表:

    1
    2
    SELECT  * FROM employee LEFT OUTER JOIN location ON employee.empID = location.empID;
    //USE OF OUTER keyword IS optional

    现在,运行此SQL的结果如下:enter image description hereenter image description here

    右外部连接:右外部联接(或右联接)与左外部联接非常相似,除非对表进行相反的处理。"右"表(位置)中的每一行将至少出现在联接表中一次。如果"左"表(Employee)中不存在匹配行,则对于位置不匹配的记录,Employee中的列将显示空值。这就是SQL的样子:

    1
    2
    SELECT * FROM employee RIGHT OUTER JOIN location  ON employee.empID = location.empID;
    //USE OF OUTER keyword IS optional

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

    enter image description hereenter image description here

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

    图像源

    mysql 8.0参考手册-连接语法

    Oracle加入操作


    内连接

    只检索匹配的行,即A intersect B

    Enter image description here

    1
    2
    3
    4
    SELECT *
    FROM dbo.Students S
    INNER JOIN dbo.Advisors A
        ON S.Advisor_ID = A.Advisor_ID

    左外连接

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

    Enter image description here

    1
    2
    3
    4
    SELECT *
    FROM dbo.Students S
    LEFT JOIN dbo.Advisors A
        ON S.Advisor_ID = A.Advisor_ID

    全外部连接

    从第二个表中选择所有记录,并选择第一个表中的所有记录与联接键匹配的表。

    Enter image description here

    1
    2
    3
    4
    SELECT *
    FROM dbo.Students S
    FULL JOIN dbo.Advisors A
        ON S.Advisor_ID = A.Advisor_ID

    工具书类

    • 内部和外部联接SQL示例和联接块

    • SQL:连接

    • 工具的名称是什么?我发现它很有趣,因为它显示了行数和维恩图
    • @Grijeshchauhan数据集市师:)
    • @trushar:(它不适用于Linux系统..
    • @Grijeshchauhan是的,但是你可以试着用酒来做。
    • 哦!是的,我……我用的是sqlyog,用的是葡萄酒……还有PlayOnLinux
    • 您的文本不清楚和错误。"仅匹配行"是从A&B&B的交叉联接中提取的行(内部联接B)不是交叉联接B,而是(左联接B)交叉(右联接B)。"所选"行不是来自A&B,而是来自A&B行的空扩展值的交叉联接B&B。


    简单来说:

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

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

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

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

    • 完整:所有表中的所有行。有没有火柴没关系

    • @不必回答这个问题,但内部联接是一个交叉点,如果左、右集合/圆中(分别)包含左、右联接的行,则完全外部联接是相应的联合。PS这个答案不清楚输入和输出中的行。它将"in the left/right table"与"has a left/right part in the left/right"混淆,并使用"matched row"与"all"来表示行从其他表扩展到行,再扩展到空。


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

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


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

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

    例如,您有一个orders和一个orderdetails表。它们通过"orderID"关联。

    命令

    • 订单编号
    • 客户名称

    订单详情

    • 有序细节
    • 订单编号
    • 产品名称
    • 数量
    • 价格

    请求

    1
    2
    3
    4
    SELECT Orders.OrderID, Orders.CustomerName
      FROM Orders
     INNER JOIN OrderDetails
        ON Orders.OrderID = OrderDetails.OrderID

    将只返回在orderdetails表中也有内容的订单。

    如果您将其更改为左外联接

    1
    2
    3
    4
    SELECT Orders.OrderID, Orders.CustomerName
      FROM Orders
      LEFT JOIN OrderDetails
        ON Orders.OrderID = OrderDetails.OrderID

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

    通过添加一个像WHERE OrderDetails.OrderID IS NULL这样的where子句,您可以使用它来查找没有任何orderdetails指示可能的孤立订单的订单。

    • 我欣赏这个简单而现实的例子。我成功地将像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 ASC这样的请求更改为SELECT 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(mysql)。我不确定附加条件,它们混合得很好…


    简单来说:

    inner join->仅从父表和子表中获取公用记录,其中父表的主键与子表中的外键匹配。

    左连接>

    伪码

    1
    2
    3
    4
    5
    6
    7
    8
    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.
        }
      }

    右连接:与左连接完全相反。在右联接中,将左联接中的表名放在右联接中的右侧,得到与左联接相同的输出。

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

    例子:

    Example

    现在假设两张桌子

    1.employees , 2.phone_numbers_employees

    1
    2
    3
    employees : id , name

    phone_numbers_employees : id , phone_num , emp_id

    这里,employees表是主表,phone_numbers_employees是子表(它包含作为连接employee.id的外键的emp_id,所以它的子表。)

    内连接

    只有当Employees表的主键(其ID)与子表Phone_Numbers_Employees(EMP_ID)的外键匹配时,才取2个表的记录。

    所以查询应该是:

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

    这里只取主键=外键上的匹配行,如上所述。这里,主键=外键上的不匹配行由于联接而被跳过。

    左连接:

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

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

    外部连接:

    1
    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

    • 结果与主键/唯一键/候选键和外键(本身)无关。巴维欧尔可以而且应该在没有参考的情况下进行描述。计算交叉联接,然后筛选出不符合条件的行;此外,对于外部联接,筛选/不匹配的行由空值扩展(每左/右/满并包括在内)。


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

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

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

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


    This is a good explanation for joins

    对于所有类型的连接,这是一个很好的图表解释。

    来源:http://ssiddique.info/understanding-sql-joins-in-easy-way.html


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

    LEFT OUTER JOINLEFT JOIN是相同的。它给出了两个表中匹配的所有记录以及左表的所有可能性。

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

    FULL JOINLEFT OUTER JOINRIGHT OUTER JOIN的组合,没有重复。


    答案是每一个的意义,所以在结果中。

    Note :
    In SQLite there is no RIGHT OUTER JOIN or FULL OUTER JOIN.
    And also in MySQL there is no FULL OUTER JOIN.

    我的答案是基于上面的笔记。

    如果有两张这样的桌子:

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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.id这样的关系向上述结果添加过滤器时,可以使用INNER JOIN

    1
    2
    3
    4
    5
    6
    7
    8
    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 JOIN:(对于右连接,只需更改表的位置)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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

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

    • 您可以在注释中添加一点,即mysql中也没有full outer join


    内部连接。

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

    外部连接。

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


    在其他答案中,我看不到关于性能和优化器的详细信息。

    有时很好地知道只有INNER JOIN是关联的,这意味着优化器有最多的选择来处理它。它可以对连接顺序进行重新排序,以便更快地保持相同的结果。优化器可以使用大多数连接模式。

    一般来说,尝试使用INNER JOIN而不是不同类型的连接是一个很好的实践。(当然,如果可以考虑预期结果集的话。)

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

    • 左外部联接是否关联?
    • SQL中的联接顺序有关系吗?

    • 使用一种类型的联接而不使用另一种类型的联接不可能是"良好实践"。您使用的联接决定了所需的数据。如果你用的是另一个,你就错了。另外,在Oracle中,至少这个答案是完全错误的。这听起来完全不对,你没有证据。你有证据吗?
    • 1。我是说试着用。我看到很多人使用左外部连接到处都没有任何好的理由。(联接列不是空的)。在这些情况下,使用内部联接肯定会更好。2。我添加了一个比我能更好地解释非关联行为的链接。
    • 据我所知,在大多数情况下,INNER JOINLEFT JOIN慢,人们可以使用LEFT JOIN而不是INNER JOIN,通过添加WHERE来删除意外的NULL结果;
    • 这些评论让我有点不确定。你为什么认为INNER慢?


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

  • 从第一张表中每行取一行:a
  • 考虑它旁边第二个表中的所有行:(a, b[i])
  • 对每一对评估ON ...条款:ON( a, b[i] ) = true/false?
    • 当条件评估为true时,返回合并行(a, b[i])
    • 当到达第二个表的末尾而没有任何匹配时,这是一个OUTER JOIN,然后使用Null为其他表的所有列返回一个(虚拟)对:(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

    注:左联接=左外联接,右联接=右外联接。


    在批评了广受欢迎的红色阴影维恩图之后,我认为发表我自己的尝试是公平的。

    虽然@martin smith的答案在很长一段时间内是最好的,但他只显示每个表中的键列,而我认为理想情况下也应该显示非键列。

    在允许的半小时内,我能做的最好的一点是,我仍然认为它不能充分地显示空值是由于TableB中没有关键值,或者OUTER JOIN实际上是一个联合而不是一个联合:

    enter image description here

    • 问题是问内部连接和外部连接之间的区别,但不一定要离开外部连接lol


    最简单的定义

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

    完全外部联接:返回两个表中匹配的和不匹配的记录,对于两个表中不匹配的记录,返回空值。

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

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

    简而言之

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

    匹配+左不匹配=左外部联接

    匹配+右不匹配=右外部联接

    匹配=内部联接

    • 这很好,解释了为什么Join不能像预期的那样在时间序列索引中工作。
    • @Yeliabsalohcin在你对这个问题的评论中,你没有解释"如预期"或"有效"。这只是一些无法解释的个人误解,你奇怪地期望别人会有。如果你在阅读的时候把单词看得很马虎——误解清楚的写作和/或接受不清楚的写作——就像你在这里写作一样,那么你可能会产生误解。事实上,像这里大多数人一样,这个答案是不清楚和错误的。"内部联接:当输入列集不同时,返回两个表中匹配的记录"是错误的。它试图说出某件事,但事实并非如此(看我的答案)。


    enter image description here

    • inner join两个或多个表的最典型联接。它返回primarykey和forignkey关系表上的数据匹配。
    • outer joininner join相同,但也包括NULL结果集的数据。
      • LEFT JOIN=inner join+左表数据不匹配,右表NULL匹配。
      • RIGHT JOIN=inner join+左表NULL匹配右表不匹配数据。
      • FULL JOIN=inner join+与NULL匹配的左、右表数据不匹配。
    • 在SQL中,当表引用自身的数据时,self-join不是关键字。使用inner joinouter join我们可以编写自连接查询。

    例如:

    1
    2
    3
    4
    5
    6
    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

    • 很好,很容易理解。


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

    它们是SQL中最常用的存在主义运算符,其中INNER JOIN用于"存在",LEFT OUTER JOIN用于"不存在"。

    考虑这些查询:

    1
    2
    users who have posted AND have votes
    users who have posted but have no badges

    寻找基于集合的解决方案(行业术语)的人会将各自的查询识别为:

    1
    2
    users who have posted INTERSECT users who have votes
    users who have posted MINUS users who have badges

    将这些转换为标准SQL:

    1
    2
    3
    4
    5
    6
    7
    SELECT UserId FROM Posts
    INTERSECT
    SELECT UserId FROM Votes;

    SELECT UserId FROM Posts
    EXCEPT
    SELECT UserId FROM Badges;

    其他人则会按照类似的集合包含方式思考:

    1
    2
    users who have posted AND IN the SET OF users who have votes
    users who have posted AND NOT IN the SET OF users who have badges

    将这些转换为标准SQL:

    1
    2
    3
    4
    5
    6
    7
    SELECT UserId
      FROM Posts
     WHERE UserId IN ( SELECT UserId FROM Votes );

    SELECT UserId
      FROM Posts
     WHERE UserId NOT IN ( SELECT UserId FROM Badges );

    有些人会考虑在集合内的"存在",例如

    1
    2
    users who have posted AND EXIST IN the SET OF users who have votes
    users who have posted AND do NOT EXIST IN the SET OF users who have badges

    将这些转换为标准SQL(注意,我们现在需要使用范围变量,即pvb

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT p.UserId
      FROM Posts p
     WHERE EXISTS ( SELECT *
                      FROM Votes v
                     WHERE v.UserId = p.UserId );

    SELECT p.UserId
      FROM Posts p
     WHERE NOT EXISTS ( SELECT *
                          FROM Badges b
                         WHERE b.UserId = p.UserId );

    但是,我发现"行业标准"方法是专门使用连接。我不知道这里的想法是什么(仪器定律?过早优化?),所以我将直接转到语法:

    1
    2
    3
    4
    5
    6
    7
    8
    SELECT p.UserId
      FROM Posts p
           INNER JOIN Votes v ON v.UserId = p.UserId;

    SELECT p.UserId
      FROM Posts p
           LEFT JOIN Badges b ON b.UserId = p.UserId
     WHERE b.UserId IS NULL;

    需要注意的事项:

    • 唯一的投影来自Users,但是我们仍然需要所有这些范围变量(pvb来搜索条件。
    • UserId IS NULL搜索条件"属于"OUTER JOIN但在查询中断开连接。
    • LEFT是行业标准:专业人员会重写查询,避免使用RIGHT
    • 省略LEFT OUTER JOIN中的OUTER关键字。

    闭幕词:

    有时连接仅用于查询,以确定值是否存在于另一个集合中。学习仔细查看正在投影的属性(SELECT子句中的列):如果联接表中没有列,则它们只是用作存在运算符。另外,对于外部连接,在WHERE子句中查找 IS NULL的实例。


    简单来说,

    1.inner join或equi join:返回仅与两个表中的条件匹配的结果集。

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

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

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

    5.完全联接:完全联接和完全外部联接相同。


    1.内部联接:也称为联接。它返回左表和右表中的行,只有在匹配时才返回。否则,它返回零个记录。

    例子:

    1
    2
    3
    4
    5
    6
    SELECT
      e1.emp_name,
      e2.emp_salary    
    FROM emp1 e1
    INNER JOIN emp2 e2
      ON e1.emp_id = e2.emp_id

    output1

    2.完全外部联接:也称为完全联接。它返回左表和右表中的所有行。

    例子:

    1
    2
    3
    4
    5
    6
    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

    连接的优点

  • 执行速度更快。
    • 只有当表具有相同的列集时,这才正确。(它混淆了内部联接和交叉点以及完全联接和并集。)也未定义"匹配"。阅读我的其他评论。


    • 内部联接-使用任一等效查询的内部联接提供两个表的交集,即它们共有的两行。

    • 左外部联接-左外部联接将提供A中的所有行,以及B中的所有公共行。

    • 完全外部联接-完全外部联接将为您提供A和B的联接,即A中的所有行和B中的所有行。如果A中的某个内容在B中没有相应的数据,则B部分为空,副versay

    • 这是错误的,也不清楚。除非表具有相同的列,否则join不是交集。外部联接没有来自A或B的行,除非它们具有相同的列,在这种情况下,不添加空值。你想说什么,但你没有说。你没有正确或清楚地解释。
    • @飞利浦:不同意你的说法。你可以连接任何你想要的列,如果值匹配,它们就会连接在一起。
    • 这个评论和你的回答一样不清楚。(我想您可能在想,结果的公共列的子程序值集是每个输入的公共列的子程序值集的交集,但这不是您所写的。你不清楚。)


    left join on(aka left outer join on返回inner join onunion all行不匹配的左表行,扩展为空。

    right join (onaka right outer join on返回inner join onunion all行不匹配的右表行,扩展为空。

    full join on(aka full outer join on返回inner join onunion all不匹配的左表行,由nulls扩展;union all不匹配的右表行,由nulls扩展。

    (SQL标准2006 SQL/FAST 7.7语法规则1,一般规则1 B,3 C和D,5 B)

    所以在你知道inner join的基础内容之前,不要使用outer join

    找出inner join返回的行。

    阅读我的评论有许多困惑和糟糕的答案。

    然后阅读我的评论这里有许多困惑和糟糕的答案。


    内部连接和外部连接的区别如下:

  • 内部联接是基于匹配元组组合表的联接,而外部联接是基于匹配和不匹配元组组合表的联接。
  • 内部联接合并两个表中的匹配行,其中省略了不匹配的行,而外部联接合并两个表中的行,不匹配的行用空值填充。
  • 内部联接类似于交叉操作,而外部联接类似于联合操作。
  • 内部联接是两种类型,而外部联接是三种类型。
  • 内部连接较慢,而外部连接比内部连接更快。

  • 考虑以下两个表:

    电磁脉冲

    1
    2
    3
    4
    5
    6
    7
    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

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

    内部连接:

    主要是作为SQL查询中的join编写的。它只返回表之间匹配的记录。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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打印Jose,因为其部门ID 6在部门表中找不到匹配项。同样,由于在EMP表中找不到匹配项,因此不会从Department表中打印HRR&D行。

    所以,内部联接或只是联接,只返回匹配的行。

    左连接:

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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

    因此,如果您观察上面的输出,那么左表(EMP)中的所有记录都将打印为右表中的匹配记录。

    HRR&D行不从部门表中打印,因为它们在部门ID的EMP表中找不到匹配项。

    所以,左联接返回左表中的所有行,并且只匹配右表中的行。

    也可以在这里查看演示。

    • 这里的任何内容都不能清楚地描述join的作用。(它也没有解决他们之间的"差异",只是说他们是不同的。)这对10年前的问题的许多答案(许多都是高度向上的)没有任何帮助——这是"有帮助的"吗?