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

sql database join inner-join outer-join

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

答案&评论&他们在 only one 下面的引用实际上解释了维恩图如何表示运算符:圆形交叉区域表示 A JOIN B 中的行集。每个圆唯一的区域表示您通过获取其表中不存在的行获得的行集t 参与 A JOIN B 并添加对另一个表唯一的列都设置为 NULL。 (而且大多数人给 A 和 B 提供了一个模糊的、虚假的圆圈对应关系。)

@DanteTheSmith 不,这与此处的图表存在相同的问题。请参阅我上面关于问题的评论和下面关于那篇博客文章的评论:“杰夫在评论中的几页拒绝了他的博客”。维恩图以集合的形式显示元素。只需尝试准确识别这些图表中的集合是什么以及元素是什么。集合不是表格,元素不是它们的行。也可以连接任意两个表,因此 PK 和 FK 无关紧要。都是假的。你所做的正是成千上万其他人所做的——得到一个模糊的印象,你(错误地)认为是有道理的。

我之前的评论是关于 a confused repudiated Jeff Atwood blog post

我的第 1 条评论的链接是外部链接,但 i.stack.imgur.com 拥有 innerleftinner输出(非输入) 插图的永久副本full 连接(绿色)。

M
Mark Harrison

假设您要加入没有重复的列,这是一种非常常见的情况:

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 部分为空,反之亦然反之亦然。

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 的外部连接给出了 A 联合 B 的结果,即维恩图联合的外部部分。措辞不准确。除了以下之一之外,外连接将给出 A 与 B 相交的结果:所有 A(左连接)、所有 B(右连接)或所有 A 和所有 B(完全连接)。只有最后一个场景才是真正的联合 B。不过,这是一个写得很好的解释。

@Ameer,谢谢。加入不保证顺序,您需要添加 ORDER BY 子句。

@Damian 是的,OUTER JOIN 和 FULL OUTER JOIN 是等价的,LEFT/RIGHT JOIN 等价于 LEFT/RIGHT OUTER JOIN,同样的 INNER JOIN 等价于一个简单的 JOIN

我对此表示反对,因为它是错误的。请考虑删除答案,因为它会误导几代计算机科学专业的学生,他们被大量的 upcote 数量所愚弄。维恩图不解释连接。连接的内部不是交集。

C
Community

维恩图并没有真正为我做这件事。

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

理解逻辑处理是无可替代的,而且无论如何都比较容易掌握。

想象一下交叉连接。针对步骤 1 中的所有行评估 on 子句,保持谓词评估为 true 的那些行(仅适用于外部连接)添加回在步骤 2 中丢失的任何外部行。

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

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

https://i.stack.imgur.com/VUkfU.gif

解释

源表

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

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

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

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

内连接和外连接有一个“ON”子句谓词。

内部联接。评估交叉连接结果中所有行的“ON”子句中的条件。如果为 true,则返回连接的行。否则丢弃它。

左外连接。与内连接相同,然后对于左表中与任何不匹配的任何行输出这些与右表列的 NULL 值。

右外连接。与内连接相同,然后对于右表中与任何不匹配的任何行输出这些与左表列的 NULL 值。

全外连接。与内连接相同,然后保留左外连接中的左不匹配行和右外连接中的右非匹配行。

一些例子

从 A.Colour 上的 A INNER JOIN B 中选择 A.Colour、B.Colour = B.Colour

以上是经典的 equi join。

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

动画版

https://i.stack.imgur.com/kZcvR.gif

SELECT A.Colour, B.Colour 从 A.Colour NOT IN ('Green','Blue') 上的 A INNER JOIN B

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

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

SELECT A.Colour, B.Colour 从 A INNER JOIN B ON 1 =1

对于交叉连接结果中的所有行,连接条件的计算结果为真,因此这与交叉连接相同。 16行的图我就不再赘述了。

从 A.Colour 的左外连接 B 中选择 A.Colour、B.Colour = B.Colour

外部联接的逻辑评估方式与内部联接相同,只是如果左表中的一行(对于左联接)根本不与右侧表中的任何行联接,则它会保留在 NULL 的结果中右侧列的值。

https://i.stack.imgur.com/4bzv2.png

从 A.Colour = B.Colour 的左外连接 B 中选择 A.Colour,B.Colour,其中 B.Colour 为 NULL

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

IS NULL 测试选择一个不可为空或连接条件可确保排除任何 NULL 值的列非常重要,以便此模式正常工作并避免只带回发生的行除了不匹配的行之外,该列还有一个 NULL 值。

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

从 A.Colour = B.Colour 的右外连接 B 中选择 A.Colour、B.Colour

右外连接的作用类似于左外连接,除了它们保留右表中不匹配的行并且空扩展左列。

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

从 A.Colour = B.Colour 的完整外部连接 B 中选择 A.Colour、B.Colour

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

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

从 1 = 0 的完整外部连接 B 中选择 A.Colour、B.Colour

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

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

选择 COALESCE(A.Colour, B.Colour) 作为颜色从 FULL OUTER JOIN B ON 1 = 0

对前面的查询稍作修改,就可以模拟两个表中的 UNION ALL

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

从 A.Colour = B.Colour 的左外连接 B 中选择 A.Colour、B.Colour 其中 B.Colour = 'Green'

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

https://i.stack.imgur.com/4bzv2.png

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

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

如果打算只包括 B 中颜色为绿色的行以及 A 中的所有行,无论正确的语法是

从 A.Colour = B.Colour 和 B.Colour = 'Green' 的左外连接 B 中选择 A.Colour、B.Colour

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

SQL小提琴

请参阅这些示例 run live at SQLFiddle.com

我会说,虽然这对我来说几乎没有维恩图那么有效,但我很欣赏人们的不同和学习方式不同,这是一个很好的解释,与我以前见过的任何不同,所以我支持@ypercube奖励积分。也很好地解释了在 JOIN 子句与 WHERE 子句中添加附加条件的区别。向你致敬,马丁·史密斯。

@OldPro 我想维恩图还可以,但它们对如何表示交叉连接或区分一种连接谓词(例如等连接)保持沉默。在交叉连接结果的每一行上评估连接谓词的心理模型,然后在外部连接中添加不匹配的行,最后评估 where 对我来说效果更好。

维恩图适用于表示联合、交叉点和差异,但不适用于连接。它们对于非常简单的连接有一些小的教育价值,即连接条件在唯一列上的连接。

@Arth - 不,你错了。 SQL Fiddle sqlfiddle.com/#!3/9eecb7db59d16c80417c72d1/5155 这是维恩图无法说明的。

你是怎么做这些动画的?很好的答案,我唯一不喜欢的是你谦虚地说维恩图不适合你。现实情况是,它们不足以模拟正在发生的事情,这很重要,以免人们产生错误的想法。

S
ScottishTapWater

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

员工

EmpID EmpName 13 杰森 8 亚历克斯 3 拉姆 17 巴布 25 约翰逊

地点

EmpID EmpLoc 13 San Jose 8 Los Angeles 3 Pune, India 17 Chennai, India 39 Bangalore, India

内连接:- 内连接通过基于连接谓词组合两个表(员工和位置)的列值来创建一个新的结果表。该查询将 Employee 的每一行与 Location 的每一行进行比较,以找到满足连接谓词的所有行对。当通过匹配非 NULL 值满足连接谓词时,Employee 和 Location 的每对匹配行的列值将组合成一个结果行。下面是内部连接的 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 Location.EmpId Location.EmpLoc 13 Jason 13 San Jose 8 Alex 8 Los Angeles 3 Ram 3 Pune, India 17 Babu 17 Chennai, India

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

左外连接:- 员工和位置表的左外连接(或简称为左连接)的结果始终包含“左”表(员工)的所有记录,即使连接条件在“右”表(位置)。下面是左外连接的 SQL 的样子,使用上面的表:

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

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

Employee.EmpId Employee.EmpName Location.EmpId Location.EmpLoc 13 Jason 13 San Jose 8 Alex 8 Los Angeles 3 Ram 3 Pune, India 17 Babu 17 Chennai, India 25 Johnson NULL NULL

请注意,虽然 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 Location.EmpId Location.EmpLoc 13 Jason 13 San Jose 8 Alex 8 Los Angeles 3 Ram 3 Pune, India 17 Babu 17 Chennai, India NULL NULL 39 印度班加罗尔

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

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

Employee.EmpId Employee.EmpName Location.EmpId Location.EmpLoc 13 Jason 13 San Jose 8 Alex 8 Los Angeles 3 Ram 3 Pune, India 17 Babu 17 Chennai, India 25 Johnson NULL NULL NULL NULL 39 印度班加罗尔

MySQL 8.0 Reference Manual - Join Syntax

Oracle Join operations

迄今为止最好的答案,替代语法 - 这就是我一直在寻找的,谢谢!

维恩图被贴错标签。请参阅我对问题和其他答案的评论。而且大多数这种语言都很差。例如:“当通过匹配非 NULL 值满足连接谓词时,每对匹配的 Employee 和 Location 行的列值将组合成一个结果行。”不,不是“当通过匹配非 NULL 值满足连接谓词时”。除了条件作为一个整体是真还是假之外,行中的值并不重要。对于真实条件,某些值很可能为 NULL。

@Persistence 表格需要的是文本,它是表格初始化代码,格式化为适合复制、粘贴和运行的列。

C
Community

内部联接

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

https://i.stack.imgur.com/Zkk3I.jpg

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

左外连接

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

https://i.stack.imgur.com/Z584b.jpg

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

全外连接

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

https://i.stack.imgur.com/c1QF3.jpg

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

参考

内连接和外连接 SQL 示例和 Join 块

SQL:连接

工具的名称是什么?我觉得这很有趣,因为它显示了行数和维恩图

@GrijeshChauhan 是的,但是您可以尝试使用 wine 运行它。

哦!是的,我..我用葡萄酒使用 SQLyog .. 还有 PlayOnLinux

您的文字不清楚且错误。 “仅匹配的行”是来自 A 和 B 的交叉连接的行,并且检索到的(A 内部连接 B)不是 A 相交 B,而是(A 左连接 B)相交(A 右连接 B)。 “选定”行不是来自 A 和 B,它们来自 A 交叉连接 B 和来自 A 和 B 的行的空扩展值。

@TusharGupta-curioustushar 您应该包括“用于 SQL 示例的表”

P
Peter Mortensen

简单来说:

内连接只检索匹配的行。

而外连接从一个表中检索匹配的行以及其他表中的所有行......结果取决于您使用的是哪一个:

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

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

完整:所有表中的所有行。有没有匹配都没关系

@nomen 不是这个答案解决了它,但是如果左右集/圆包含(分别)左和右连接的行,则 INNER JOIN 是一个交集,而 FULL OUTER JOIN 是相应的 UNION。 PS这个答案不清楚输入与输出中的行。它将“在左/右表中”与“在左/右中具有左/右部分”混淆了,它使用“匹配行”与“全部”来表示从其他表中按行扩展的行与按空值扩展的行。

1
1800 INFORMATION

内连接仅在连接的另一(右侧)存在匹配记录时才显示行。

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

S
SergeyYu

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

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

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

订单

订单编号

顾客姓名

订单详细信息

订单详情 ID

订单编号

产品名称

数量

价格

请求

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

只会返回在 OrderDetails 表中也有内容的订单。

如果将其更改为 OUTER LEFT JOIN

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)。我不确定附加条件,它们混合得很好......

C
Community

简单来说:

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

左连接->

伪代码

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 中的所有记录。如果左表中的记录根据Primary,Forieign key与右表不匹配,则使用NULL值作为连接结果。

例子 :

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

现在让我们假设 2 个表

1.employees , 2.phone_numbers_employees

employees : id , name 

phone_numbers_employees : id , phone_num , emp_id   

这里,employees 表是 Master 表,phone_numbers_employees 是子表(它包含 emp_id 作为外键连接 employee.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;

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

https://i.stack.imgur.com/hMKKt.jpg

结果与主/唯一/候选键和外键无关(本身)。 baviour 可以而且应该在不参考它们的情况下进行描述。计算一个交叉连接,然后过滤掉不符合 ON 条件的行;此外,对于外连接行,过滤/不匹配的行由 NULL 扩展(每个 LEFT/RIGHT/FULL 并包括在内。

SQL 连接始终是主键/外键匹配的假设导致了对维恩图的这种滥用。请相应地修改您的答案。

s
shA.t

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

OUTER JOIN 中,结果表可能有空列。外部联接可以是 LEFTRIGHT

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

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

A
A_Pointar

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

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

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

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

s
shA.t

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

注意:在 SQLite 中没有 RIGHT OUTER JOIN 或 FULL OUTER JOIN。而且在 MySQL 中也没有 FULL OUTER JOIN。

我的回答是基于上面的注释。

当您有两个这样的表时:

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

CROSS JOIN / OUTER JOIN :
您可以使用 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

INNER JOIN :
当您想根据 table1.id = table2.id 之类的关系向上述结果添加过滤器时,可以使用 INNER 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 :
当您希望上述结果中的一个表的所有行具有相同的关系时,您可以使用 LEFT JOIN
(对于 RIGHT 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

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

您可以在注释中添加,MySQL 中也没有 full outer join

S
Sandesh

内部联接。

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

外连接。

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

P
Premraj

https://i.stack.imgur.com/TBMzF.jpg

INNER JOIN 最典型的两个或多个表的连接。它返回表 ON primarykey 和 forignkey 关系上的数据匹配。

OUTER JOIN 与 INNER JOIN 相同,但它还包括 ResultSet 上的 NULL 数据。 LEFT JOIN = INNER JOIN + 左表不匹配数据与右表空匹配。 RIGHT JOIN = INNER JOIN + 右表的不匹配数据与左表的空匹配。 FULL JOIN = INNER JOIN + 左右表上的不匹配数据与 Null 匹配。

LEFT JOIN = INNER JOIN + 左表不匹配数据与右表空匹配。

RIGHT JOIN = INNER JOIN + 右表的不匹配数据与左表的空匹配。

FULL JOIN = INNER JOIN + 左右表上的不匹配数据与 Null 匹配。

自联接不是 SQL 中的关键字,当表本身引用数据时称为自联接。使用 INNER JOIN 和 OUTER 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 
C
Community

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

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

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

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

左外连接是关联的吗?

连接顺序在 SQL 中重要吗?

使用一种类型的连接而不是另一种类型的连接不可能是“好习惯”。您使用的连接决定了您想要的数据。如果你使用不同的,那你就错了。另外,在 Oracle 中,至少这个答案是完全错误的。这听起来对一切都完全错误,你没有证据。你有证据吗?

1.我的意思是尝试使用。我看到很多人在没有任何充分理由的情况下到处使用 LEFT OUTER 连接。 (连接的列不为空。)在这些情况下,使用 INNER 连接肯定会更好。 2. 我添加了一个链接,可以更好地解释非关联行为。

据我所知,INNER JOIN 在大多数情况下都比 LEFT JOIN 慢,人们可以通过添加 WHERE 来使用 LEFT JOIN 而不是 INNER JOIN 来删除意外的 NULL 结果;)。

这些评论让我有点不确定。为什么您认为 INNER 较慢?

取决于发动机。 gnu join、joinkeys、DB2、MySQL。性能陷阱比比皆是,例如松散类型或显式转换。

o
onedaywhen

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

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

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

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

问题是询问 INNER 和 OUTER 连接之间的差异,但不一定是左外连接

@LearnByReading:我右边的图片是右外连接,即用 TableB B RIGHT OUTER JOIN TableA a 替换 TableA a LEFT OUTER JOIN TableB b

S
S.Serpooshan

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

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

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

... ON T1.title = T2.title AND T1.version < T2.version (=> 将此帖子视为示例用法:仅选择列上具有最大值的行)

... ON T1.y 为空

... ON 1 = 0(就像示例一样)

https://i.stack.imgur.com/0dWzY.png

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

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

A
Akshay Khale

最简单的定义

内连接:从两个表中返回匹配的记录。

完全外连接:返回两个表中匹配和不匹配的记录,对于两个表中的不匹配记录返回 null。

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

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

简而言之

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

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

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

匹配 = 内连接

这太棒了,并解释了为什么 join 不能按预期对时间序列索引起作用。相隔一秒的时间戳是无与伦比的。

@yeliabsalohcin您没有在此处解释“按预期”或在您对问题的评论中“有效”。这只是你奇怪地期望别人有的一些无法解释的个人误解。如果您在阅读时将单词视为草率-误解清晰的写作和/或接受不清晰的写作-就像您在这里写作时一样,那么您可能会产生误解。事实上,像这里的大多数人一样,这个答案是不清楚和错误的。当输入列集不同时,“内部联接:从两个表中返回匹配的记录”是错误的。它试图说某件事,但事实并非如此。 (见我的回答。)

C
Community

总体思路

请参阅 Martin Smithanswer,以更好地说明和解释不同的连接,尤其是 FULL OUTER JOINRIGHT OUTER JOINLEFT OUTER JOIN 之间的区别。

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

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

交叉连接

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

SELECT *
  FROM citizen
 CROSS JOIN postalcode

结果将是所有组合的笛卡尔积。不需要 JOIN 条件:

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

内部联接

INNER JOIN 与简单的相同:JOIN

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

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

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

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

左外连接

LEFT OUTER JOINLEFT JOIN 相同

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

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

结果将是 citizen 中的所有内容,即使 postalcode 中没有匹配项。再次需要一个 JOIN 条件:

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

播放数据

所有示例都在 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;

使用 JOIN 和 WHERE 时边界模糊

交叉连接

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

使用 CROSS JOIN 获取 LEFT OUTER JOIN 的结果需要一些技巧,例如添加 NULL 行。它被省略了。

内部联接

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

这就是内部连接可以真正被视为交叉连接的地方,其结果与删除的条件不匹配。这里没有任何结果行被删除。

使用 INNER JOIN 获得 LEFT 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 external”上的图像互联网搜索将显示大量维恩图。我曾经在我的桌子上放了一份印刷版。但表示存在问题。

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

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

在下面的讨论中,集合 A 表示左侧的集合(citizen 表),集合 B 是右侧的集合(postalcode 表)。

交叉连接

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

行是不同的。 UNION 共有 7 行。但它们与常见的 SQL 结果集不兼容。这根本不是 CROSS JOIN 的工作方式:

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

试图像这样表示它:

https://i.stack.imgur.com/1BhEE.png

..但现在它看起来就像一个 INTERSECTION,它肯定 不是。此外,INTERSECTION 中没有任何元素实际上位于两个不同集合中的任何一个中。但是,它看起来很像类似这样的可搜索结果:

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

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

内部联接

元素的值取决于 JOIN 条件。在每一行都对该条件唯一的条件下表示这一点是可能的。含义 id=x 仅适用于 one 行。一旦表 A (citizen) 中的一行在 JOIN 条件下匹配表 B (postalcode) 中的多行,结果与 CROSS JOIN 存在相同的问题:该行需要多次表示,而集合论并不是为此而生的。在唯一性条件下,图表可以工作,但请记住,JOIN 条件决定了元素在图表中的位置。仅查看 JOIN 条件的值以及该行的其余部分以进行乘车:

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

当使用带有 ON 1 = 1 条件的 INNER JOIN 使其成为 CROSS JOIN 时,此表示完全崩溃。

使用 self-JOIN,行实际上是两个表中的相同元素,但将表同时表示为 AB 不是很合适。例如,使 A 中的元素与 B 中的 不同 元素匹配的常见 self-JOIN 条件是 ON A.parent = B.child,使得从 A 匹配到 B单独的元素。从像这样的 SQL 示例中:

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

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

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

外连接

当一行与另一表中的行有多个匹配时,麻烦再次开始。这更加复杂,因为 OUTER JOIN 可以被认为是匹配空集。但是在集合论中,任何集合 C 和一个空集的并集总是只是 C。空集什么也没增加。这个 LEFT OUTER JOIN 的表示通常只是显示所有 A 来说明无论是否有来自 B 的匹配,都会选择 A 中的行。然而,“匹配元素”具有与上图相同的问题。它们取决于条件。空集似乎已经徘徊到 A

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

WHERE 子句 - 有意义

在月球上查找带有 Smith 和邮政编码的 CROSS JOIN 中的所有行:

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

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

现在不使用维恩图来反映 JOIN。它用于 WHERE 子句:

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

..这是有道理的。

当 INTERSECT 和 UNION 有意义时

相交

如前所述,INNER JOIN 并不是真正的 INTERSECT。但是 INTERSECT 可以用于单独查询的结果。这里的维恩图很有意义,因为来自单独查询的元素实际上是属于一个结果或两者的行。相交显然只会返回两个查询中都存在该行的结果。此 SQL 将产生与上述 WHERE 相同的行,维恩图也将相同:

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

联盟

OUTER JOIN 不是 UNION。但是 UNION 在与 INTERSECT 相同的条件下工作,导致返回结合两个 SELECT 的所有结果:

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

..并给出结果:

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

这里的维恩图也很有意义:

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

不适用时

一个重要的注意事项是,这些仅在两个 SELECT 的结果结构相同时才有效,从而可以进行比较或联合。这两个结果将无法实现:

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

..尝试将结果与 UNION 结合起来

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

如需更多兴趣,请阅读 Say NO to Venn Diagrams When Explaining JOINssql joins as venn diagram。两者都涵盖EXCEPT

A
Anands23

简单来说,

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

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

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

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

5.FULL JOIN:完全连接和完全外连接是一样的。

p
philipxy

left join on 返回由 null 扩展的 inner join onunion all 不匹配的左表行。

right join on 返回由 null 扩展的 inner join onunion all 不匹配的右表行。

full join on 返回 inner join onunion allnulls 扩展的不匹配的左表行 union allnulls 扩展的不匹配的右表行。

outer 是可选的没有效果。

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

因此,在您知道所涉及的基础 inner join on 之前,不要outer join on

找出行 inner join on 返回的内容:CROSS JOIN vs INNER JOIN in SQL

这也解释了为什么维恩(类)图对内连接和外连接没有帮助。要详细了解为什么它们通常对连接没有帮助:Venn Diagram for Natural Join

我确实阅读了您的许多评论。当您说“正确解释的维恩图可以表示内部连接与外部连接”时,您是指由观察者正确解释还是维恩图本身?如果是后者,请画出来:)

我不确定你想说什么。我说的是维恩图作为元素集的标准解释。 (因为图表的某些用途甚至无法做到这一点。)应用程序的“正确”包括说明集合和/或元素是什么。请参阅本页顶部的评论,其中有 50 人对内连接和外连接的维恩图表示赞同。我将在这个问题中编辑我的一些评论。我不想在这篇文章中使用维恩图。

我也不想要维恩图!

我必须承认,尽管我在评论中快速措辞,因为 SQL 涉及包和空值,并且 SQL 文化没有通用术语来命名和区分相关概念,即使清楚地解释维恩图的元素如何与输出“行”是 1:1,更不用说输入“行”了。或者内部或外部联接做什么,更不用说它们的区别了。 “value”可能包含也可能不包含 NULL,“row”可能是值列表 vs 表值或变量中的插槽 & “=”可能是 SQL “=” vs 相等性。

类似于我们的笛卡尔积与关系积讨论,我怀疑维恩图对于已经了解连接类型之间差异的人们来说很有意义!

S
Sandesh

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

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

全外连接 - 全外连接将为您提供 A 和 B 的并集,即 A 中的所有行和 B 中的所有行。如果 A 中的某些内容在 B 中没有对应的数据,则 B 部分是为空,反之亦然

这是错误的和不清楚的。除非表具有相同的列,否则联接不是交集。外部联接没有来自 A 或 B 的行,除非它们具有相同的列,在这种情况下不会添加空值。你试图说些什么,但你没有说出来。您没有正确或清楚地解释。

@philipxy:不同意您的陈述Join is not an intersection unless the tables have the same columns不。您可以加入任何您想要的列,如果值匹配,它们将连接在一起。

该评论与您的答案一样不清楚。 (我想你可能会想,结果的公共列的子行值集是每个输入的公共列的子行值集的交集;但这不是你写的。你不清楚。)

我的意思是,当它是具有相同列的输入的自然内部连接时,连接只是输入的交集。您错误地使用了“交集”和“联合”这两个词。

L
Laxmi

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

https://i.stack.imgur.com/lWzlz.jpg

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

例子:

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

https://i.stack.imgur.com/3yY0Y.jpg

3.Left Outer join:或者简称为Left Join。它返回左表中存在的所有行以及右表中的匹配行(如果有)。

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

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

连接的优点

执行速度更快。

仅当表具有相同的列集时,这才是正确的。 (它将内连接与交集和完全连接与联合混淆。)“匹配”也是未定义的。阅读我的其他评论。

H
HGG-Dev

通过一个示例可以更轻松地解释连接:

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

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

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

内部联接

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

仅显示匹配的 ID 行。

外连接

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

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

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

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

https://i.stack.imgur.com/736nT.png

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

M
Mayank Porwal

考虑以下 2 个表格:

电磁脉冲

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

正如您在上面看到的,Jose 不是从输出中的 EMP 打印的,因为它的 dept_id 6 在 Department 表中找不到匹配项。同样,HRR&D 行不会从 Department 表中打印出来,因为它们在 Emp 表中没有找到匹配项。

因此,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 表中的匹配记录一起打印。

HRR&D 行未从 Department 表中打印,因为它们未在 dept_id 的 Emp 表中找到匹配项。

因此,LEFT JOIN 返回左表中的所有行,并且只返回右表中的匹配行。

也可以查看 DEMO here

p
philipxy

inner joinouter join 的区别如下:

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

外连接结果与内连接相同,但加上一些额外的行,所以我不知道你为什么认为外连接会更快。还有这些“两种类型”的内连接是什么?我想您指的是外部的完整,左侧和右侧?

外连接并不比内连接快。

p
philipxy

这里有很多很好的答案以及非常准确的 relational algebra 示例。这是一个非常简化的答案,可能对遇到 SQL 编码困境的业余或新手编码员有所帮助。

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

对于 A 数据子集的 SELECT

当您要查找的相关 B 数据必须在每个数据库设计中存在时,请使用 INNER JOIN;

当您正在寻找的相关 B 数据可能或可能不存在每个数据库设计时,请使用 LEFT JOIN。

N
Nathan Long

一个示范

设置

跳到 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;

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

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

FULL OUTER JOIN 返回所有人类和所有猫,如果两边都没有匹配项,则返回 NULL

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

LEFT OUTER JOIN 返回所有人类(左表)。任何没有猫的人都会在 cat_name 列中获得 NULL。任何没有人的猫都被排除在外。

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

RIGHT OUTER JOIN 返回所有猫(右表)。任何没有人类的猫都会在 human_name 列中获得 NULL。任何没有猫的人都被排除在外。

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

内部与外部

您可以看到,虽然 INNER JOIN 只获得匹配对,但每种 OUTER 连接都包含一些没有匹配项的项目。

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

JOIN 本身意味着 INNER

LEFT JOIN、RIGHT JOIN 和 OUTER JOIN 都暗示 OUTER

最佳答案,但仍然是桶底。这有什么意义?

4
41 72 6c

内连接VS。外连接

在 SQL 中,join 用于比较和组合——字面意思是 join——并从数据库中的两个或多个表中返回特定的数据行。 INNER JOIN 从表中查找并返回匹配数据,而 OUTER JOIN 从表中查找并返回匹配数据和一些不同的数据。

内部联接

INNER JOIN 侧重于 2 个表之间的相似性。使用 INNER JOIN 时,要比较的两个(或多个)表之间必须至少有一些匹配的数据。 INNER JOIN 搜索表以查找匹配或重叠的数据。如果找到,INNER JOIN 会组合信息并将其返回到新表中。

例子

让我们考虑一个有两个表的常见场景:产品价格和数量。两个表中的共同信息是产品名称,所以这是连接表的逻辑列。有些产品在两个表中是相同的;其他人对一个人来说是独一无二的,并且在另一个人中没有匹配项。

产品 INNER JOIN 仅返回两个表共有的产品信息。

我整理了一些 HTML 和 CSS 的交互,以便您可以直观地想象整个事情。

/* CSS 样式 */ .circles { display: flex; } .circle { 高度:100px;宽度:100px;边界半径:50%;背景:#99AEBA; } .circle:first-child { 背景:#FF0000; } .circle:nth-child(2) { 背景:#05E156;变换:translateX(-45px); z指数:2;混合混合模式:乘法; } INNER JOIN

此处红色圆圈描述您的 PRICES,绿色圆圈描述您的 QUANTITIES

价格 数量

P.产品 P.价格 Q.产品 Q.数量 A 6€ A 92 B 5€ B 27 C 5€ D 66 D 1€ E 20

如果您现在想要一个确定交集的 INNER JOIN,您可以编写以下查询:

SELECT Prices.*, Quantities.Quantity
FROM Prices INNER JOIN Quantities
ON Prices.Product = Quantities.Product;

作为交叉点,您现在从图中获得黑色区域,并得出以下查询结果:

产品 价格 数量 A 6€ 92 B 5€ 27 D 1€ 66

外连接

OUTER JOIN 返回一组记录(或行),其中包含 INNER JOIN 将返回的内容,但包含在另一个表中未找到对应匹配项的其他行。

外连接分为三种类型:

左外连接(或左连接)

右外连接(或右连接)

FULL OUTER JOIN(或完全连接)

这些 OUTER JOIN 中的每一个都指的是被比较、组合和返回的数据部分。有时会在此过程中生成零,因为某些数据是共享的,而另一些则不是。

但是,这种描述现在超出了问题的范围。

我的资料来源:https://www.diffen.com/difference/Inner_Join_vs_Outer_Join https://www.freecodecamp.org/news/sql-join-types-inner-join-vs-outer-join-example/#:~: text=%20最大%20差异%20%20an,table%20in%20the%20resulting%20table。 https://towardsdatascience.com/what-is-the-difference-between-an-inner-and-an-outer-join-in-sql-5b5ec8277377