“内部连接”和“外部连接”有什么区别?

LEFT OUTER JOINRIGHT OUTER JOINFULL OUTER JOIN是如何实现的?

2557454 次浏览

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

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

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

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

例如,您有一个Orders和一个Order详细信息表。它们由“OrderID”关联。

订单

  • 订单号
  • 客户名称

订单详情

  • 订单详情订单号
  • 订单号
  • 产品名称产品名称
  • 数量
  • 价格

该请求

SELECT Orders.OrderID, Orders.CustomerNameFROM OrdersINNER JOIN OrderDetailsON Orders.OrderID = OrderDetails.OrderID

只会返回Order详细信息表中也有内容的订单。

如果您将其更改为OUTER LEFT JOIN

SELECT Orders.OrderID, Orders.CustomerNameFROM OrdersLEFT JOIN OrderDetailsON Orders.OrderID = OrderDetails.OrderID

然后它将返回Orders表中的记录,即使它们没有Order详细记录。

您可以通过添加WHERE OrderDetails.OrderID IS NULL之类的where子句来使用它来查找没有任何指示可能的孤立订单的订单。

假设你加入没有重复项的列,这是一个非常常见的情况:

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

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

示例

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

A    B-    -1    32    43    54    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 | 34 | 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 | null2 | null3 |    34 |    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    |  34    |  4null |  5null |  6

完全外连接

一个完整的外连接将给你A和B的并集,即A中的所有行和B中的所有行。如果A中的某些内容在B中没有对应的数据,则B部分为空,反之亦然。

select * from a FULL OUTER JOIN b on a.a = b.b;
a   |  b-----+-----1 | null2 | null3 |    34 |    4null |    6null |    5

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

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

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

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

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

#0中,结果表可能有空列。外连接可以是LEFTRIGHT

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

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

简单的一句话:

内连接仅检索匹配的行。

外连接从一个表中检索匹配的行和另一个表中的所有行……结果取决于您使用的是哪一个:

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

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

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

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

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

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

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

内连接

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

在此输入图片描述

SELECT *FROM dbo.Students SINNER JOIN dbo.Advisors AON S.Advisor_ID = A.Advisor_ID

左外连接

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

在此输入图片描述

SELECT *FROM dbo.Students SLEFT JOIN dbo.Advisors AON S.Advisor_ID = A.Advisor_ID

完全外连接

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

在此输入图片描述

SELECT *FROM dbo.Students SFULL JOIN dbo.Advisors AON S.Advisor_ID = A.Advisor_ID

参考文献

内部连接。

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

外连接。

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

维恩图对我来说并没有真正做到这一点。

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

理解逻辑处理是没有替代的,无论如何,它是相对简单的掌握。

  1. 想象一个交叉连接。
  2. 针对步骤1中的所有行计算on子句,保留谓词计算为true的那些行
  3. (仅适用于外连接)添加回步骤2中丢失的任何外行。

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

我将从全外连接的动画版本开始。

在此处输入图片描述


补充说明

源表格

在此处输入链接描述

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

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

在此处输入链接描述

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

  • 内部连接。为交叉连接结果中的所有行评估“ON”子句中的条件。如果为true,则返回连接的行。否则丢弃它。
  • 左外接。与左表中任何不匹配任何内容的行的内连接相同,右表列输出NULL值。
  • 右外连接。与右表中任何不匹配任何内容的行的内连接相同,为左表列输出NULL值。
  • 全外接。与内连接相同,然后保留左向外连接中的左非匹配行和右向外连接中的右非匹配行。

一些例子

在A. Colour=B. Colour上从内部作业B中选择A. Colour, B. Colour

以上是经典的equi连接。

内连接

动画版

在此处输入图片描述

SELECT A. Colour, B. Colour from A INNER JOIN B ON A.颜色不在('Green','Blue')

内连接条件不一定是相等条件,也不一定要引用表中的列。

内部2

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

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

选择A. Colour, B. Colour从一个左外连接B在A. Colour=B. Colour

外连接的逻辑计算方式与内连接相同,只是如果左表中的行(对于左连接)根本不与右表中的任何行连接,则它会保留在结果中,右手列的值为NULL

LOJ

在A. Colour=B. Colour中选择A. Colour, B. Colour从左外接任务B中选择A. Colour, B. Colour

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

重要的是要为IS NULL测试选择一个不可为空的列,或者连接条件确保任何NULL值都将被排除在外,以便该模式正常工作,并避免仅仅带回除了未匹配的行之外该列恰好具有NULL值的行。

loj is null

在A. Colour=B. Colour上从右外连接B中选择A. Colour, B. Colour

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

ROJ

在A. Colour=B. Colour上从一个完整的外部连接B中选择A. Colour, B. Colour

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

FOJ

选择A. Colour, B. Colour从一个完整的外部连接B on 1=0

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

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其中B. Colour='Green'

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

LOJ

NULL= 'Green'不计算为true,因此由外部连接保留的行最终被丢弃(与蓝色的行一起),有效地将连接转换回内部连接。

日志内容

如果目的是只包括来自B的行,其中Colour是Green,而所有来自A的行,无论正确的语法是

选择A. Colour, B. Colour从一个左外连接B上的A. Colour=B. Colour and B. Colour='Green'

输入图片描述

SQL小提琴

请参阅这些示例运行在SQLFiddle.com

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

雇员

帝国情报局 姓名
13 杰森
8 亚历克斯
3 战羊
17 媳妇儿
25 约翰逊

地点

帝国情报局 雇员公积金计划
13 圣何塞
8 洛杉矶
3 浦那
17 金奈
39 印度班加罗尔

内部连接:- 内部连接通过根据连接谓词组合两个表(雇员地点)的列值来创建一个新的结果表。该查询将 雇员的每一行与 地点的每一行进行比较,以查找满足 join-谓词的所有行对。当通过匹配非 NULL 值来满足连接谓词时,将 雇员地点的每对匹配行的列值合并到一个结果行中。 下面是内部连接的 SQL:

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

现在,下面是运行这个 SQL 的结果:

雇员 雇员,姓名 地点: EmpId 地点,就业中心
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 战羊 3 浦那
17 媳妇儿 17 金奈

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

左外连接:-雇员地点的左外部连接(或简单的左连接)的结果总是包含“ left”表(雇员)的所有记录,即使连接条件在“ right”表(地点)中没有找到任何匹配记录。 使用上面的表,左外部连接的 SQL 是这样的:

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

现在,下面是运行这个 SQL 的结果:

雇员 雇员,姓名 地点: EmpId 地点,就业中心
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 战羊 3 浦那
17 媳妇儿 17 金奈
25 约翰逊 无效 无效

注意,虽然 Johnson 在 Employerlocation 表中没有条目,但是它仍然包含在结果中,但是 location 字段为空。

右外连接:- 右外联接(或右联接)非常类似于左外联接,只是对表的处理是相反的。“ right”表(地点)中的每一行将至少出现在联接表中一次。如果“ left”表(雇员)中没有匹配的行,那么对于那些在 地点中没有匹配的记录,在 雇员中的列中将显示 NULL。 这就是 SQL 的样子:

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

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

雇员 雇员,姓名 地点: EmpId 地点,就业中心
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 战羊 3 浦那
17 媳妇儿 17 金奈
无效 无效 39 印度班加罗尔

请注意,虽然没有列出在 Bangalore 工作的雇员,但是它仍然包含在结果中,并且雇员字段为空。

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

雇员 雇员,姓名 地点: EmpId 地点,就业中心
13 杰森 13 圣何塞
8 亚历克斯 8 洛杉矶
3 战羊 3 浦那
17 媳妇儿 17 金奈
25 约翰逊 无效 无效
无效 无效 39 印度班加罗尔

MySQL 8.0参考手册-连接语法

Oracle 连接操作

简而言之:

内部连接 -> 从父表和子表中取出仅有的通用记录父表的 WHERE 主键与子表中的 Foreign key 匹配。

左连接 ->

伪代码

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中的所有记录。如果左表中的记录与基于主键、外键的右表不匹配,则使用 NULL 值作为连接的结果。

例如:

Example

现在假设有两张表

1.employees , 2.phone_numbers_employees

employees : id , name


phone_numbers_employees : id , phone_num , emp_id

在这里,Employestable 是 Master 表,phone _ number _ 員是子表(它包含 emp_id作为连接 employee.id的外键,因此它的子表也包含 emp_id)

内连接处

取2个表 雇员表(其 id)的主键匹配子表 phone _ number _ employee (emp _ id)的外键的记录。

所以问题是:

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

答案在于每个问题的意义,也在于结果。

注:
SQLite中没有 RIGHT OUTER JOINFULL OUTER JOIN
MySQL中也没有 FULL 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.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 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:

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

那么,根据你的需要,你选择每一个可以满足你的需要的;)。

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

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

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

enter image description here

  • 内部连接 -使用任何一个等效查询的 内部连接给出两个 桌子的交集,即它们共有的两行。

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

  • 完全外部连接 -A 全外连接,全外连接将给出 A 和 B 的联合,即 A 中的所有行和 B 中的所有行。如果 A 中的某个数据在 B 中没有对应的数据,那么 B 部分为空,反之亦然

最简单的定义

内部连接: 从两个表返回 匹配记录

完全外部连接: 从两个表返回匹配的和 无与伦比的记录,对于来自 两张桌子的未匹配记录返回 null。

左外联接: 只从 左边上的表返回匹配和不匹配的记录。

右外部连接: 仅从 右边上的表返回匹配的和未匹配的记录。

简而言之

匹配 + 左无匹配 + 右无匹配 = 全外连接

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

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

匹配 = 内部连接

简单来说,

返回只与两个表中的条件匹配的结果集。

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

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

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

5. 全体加入:全连接和全外连接是相同的。

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

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

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

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

注意: Left Join = Left foreign Join,Right Join = Right foreign foreign Join。

1.也称为加入。它返回左表和右表中都存在的行,只返回 如果有匹配的话。否则,它将返回零条记录。

例如:

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.左外连接:或简称为“左连接”。它返回 Left 表中的所有行以及右表中匹配的行(如果有的话)。

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

joins

连接的优点

  1. 执行速度更快。

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

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

full join on返回由 nulls 扩展的 inner join on rowsunion all不匹配的左表行,由 nulls 扩展的 union all不匹配的右表行。

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返回的行: SQL 中的交叉连接与内部连接

这也解释了为什么维恩(类似)图对内部连接和外部连接没有帮助。 要了解更多关于它们对连接通常没有帮助的原因: 自然连接的维恩图

inner joinouter join的区别如下:

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

enter image description here

  • INNER JOIN最典型的两个或多个表的联接。 它返回表 ON 主键和外键关系上的数据匹配。
  • OUTER JOININNER JOIN相同,但它也包括 ResultSet 上的 NULL数据。
    • 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

考虑以下两个表:

电磁脉冲

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 查询中,大部分都是以 加入的形式编写的,它只返回表之间的匹配记录。

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

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,因为它的 dept _ id 6在 Department 表中没有找到匹配项。类似地,HRR&D行不会从 税务局表中打印出来,因为它们在 Emp 表中没有找到匹配的行。

因此,INERJOIN 或者只是 JOIN 只返回匹配的行。

左连接:

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

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)中的所有记录都只打印右表中的匹配记录。

HRR&D行没有从 税务局表中打印出来,因为它们在 dept _ id 的 Emp 表中没有找到匹配的行。

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

也可以检查示例 给你

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

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

对于 A数据子集的 SELECT:

  • 使用 INNER JOIN时,相关的 B数据你正在寻找的 必须的存在每个数据库设计;
  • 使用 LEFT JOIN时,相关的 B数据,您正在寻找的 也许吧也许不会存在每个数据库设计。

概念

请参阅 马丁 · 史密斯中的 回答,以便更好地说明和解释不同的连接,包括特别是 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

即使在 postalcode中没有匹配,结果也将是 citizen中的所有内容。同样需要 JOIN条件:

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的结果是一行行的总体思路/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 Ideas/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的结果如下:

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

LEFT 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 连接交叉内部外部”将显示大量的维恩图。我曾经在我的桌子上有一份打印的复印件。但是代表权有问题。

维恩图对于集合论来说是极好的,其中一个元素可以在一个或两个集合中。但是对于数据库,在我看来,一个“集合”中的一个元素似乎是表中的一行,因此不会出现在任何其他表中。在多个表中不存在一行这种情况。行对于表来说是唯一的。

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

集合 A表示左边的集合(citizen表) ,集合 B表示右边的集合(postalcode表)。

交叉连接

两个集合中的每个元素都与另一个集合中的每个元素相匹配,这意味着我们需要每个 B元素的 A数量和每个 A元素的 B数量来恰当地表示这个笛卡儿积。集合理论不适用于一个集合中的多个相同元素,所以我发现用维恩图来恰当地表示它是不切实际的/不可能的。看起来 UNION完全不符合。

行数很清楚。UNION总共有7行。但是它们对于一个常见的 SQL结果集是不兼容的。CROSS JOIN完全不是这样工作的:

CrossJoinUnion1

试着用这样的方式来表达:

CrossJoinUnion2Crossing

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

CrossJoinUnionUnion3

作为参考,在 教程入口上可以看到一个 CROSS JOIN的可搜索结果。 INTERSECTION,就像这个一样,是空的。

内连接

元素的值取决于 JOIN条件。在每一行都是唯一的条件下表示它是可能的。意味着 id=x只对 id=x0行为真。一旦表 A(citizen)中的一行在 JOIN条件下与表 B(postalcode)中的多行匹配,结果就会出现与 CROSS JOIN相同的问题: 该行需要多次表示,而集合理论实际上并不适用于此。在唯一性条件下,图可以工作,但是请记住,JOIN条件决定了元素在图中的位置。只看 JOIN条件的值与其他行只是沿乘坐:

InnerJoinIntersection - Filled

当使用具有 ON 1 = 1条件的 INNER JOIN使其变成 CROSS JOIN时,这种表示完全分离。

使用自 JOIN,行实际上是两个表中的标识元素,但是将表表示为 AB并不十分合适。例如,使得 A中的元素与 B 中的 与众不同元素匹配的一个常见的自我 JOIN条件是 ON A.parent = B.child,使得从 AB的匹配是在单独的元素上进行的。从这样的 SQL的例子来看:

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

SelfJoinResult

意思是史密斯是格林和詹森的领袖。

外连接

同样,当一行与另一个表中的行有多个匹配时,问题就开始了。这更加复杂,因为 OUTER JOIN可能与空集匹配。但是在集合论中,任意一个集合 C和一个空集合的并总是 C。空的集合没有增加任何东西。这个 LEFT OUTER JOIN的表示通常只是显示所有的 A,以说明无论是否有来自 B的匹配,都选择了 A中的行。然而,“匹配元素”与上图有相同的问题。要看情况而定。而这个空的集合似乎已经转移到了 A:

LeftJoinIntersection - Filled

WHERE 子句-有意义

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

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

Where - result

现在,维恩图不用来反映 JOIN,而是用 只有来表示 WHERE子句:

Where

这就说得通了。

当 INTERSECT 和 UNION 有意义的时候

互联系统

正如解释的那样,INNER JOIN实际上并不是 INTERSECT。然而,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';

并给出了结果:

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

如果想了解更多,请阅读 在解释连接时对维恩图说不Sql 作为维恩图连接。它们也涵盖 EXCEPT

用一个例子更容易解释连接:

enter image description here

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

表 A 和表 B 由 Table _ A. 身份证 = 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 上不可用

示范

设置

跳入 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返回所有的 cat (右表)。 任何没有人类的猫都会在 human_name列中得到 NULL。 没有猫的人被排除在外。

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

内心对抗外在

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

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

  • JOIN本身意味着 INNER
  • LEFT JOINRIGHT JOINOUTER JOIN都暗示 OUTER

“外部”和“内部”只是可选的元素,您只需要处理两种(三种)连接。内部连接(或者只使用“ join”时的默认值)是一个连接,其中只有匹配条件的元素出现在两个表上。

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

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

总之,如果我们有这样的表 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 史波克

在 Inside join 中,我们可以检索不同表中具有相同/相关数据的数据

选择 Sname,Tname 来自学生的 加入 T 老师 ON s.id = t.id;

在这种情况下,如果您还希望从不同的表中获取其他数据信息,那么可以使用外部连接

我们有三种外接头:

左连接,右连接,全连接

我们还将从 左外连接。的左边(第一个)表中检索不相关的数据

选择 Sname,Tname 来自学生的 左加入 T 老师 ON s.id = t.id;

右外连接中,我们还从右边的表(第二个表)中检索不相关的数据

选择 Sname,Tname 来自学生的 加入 T 老师 ON s.id = t.id;

当我们想从两个表中检索所有/完整的数据时,可以使用 全外连接,缺少的数据将用 NULL 填充。

选择 Sname,Tname 来自学生的 全体加入 T 老师 ON s.id = t.id;