繁体   English   中英

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

[英]What is the difference between "INNER JOIN" and "OUTER JOIN"?

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

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

  • 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

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

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

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

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

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

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

在此处输入图像描述


解释

源表

在此处输入链接描述

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

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

在此处输入链接描述

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

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

一些例子

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

以上是经典的 equi join。

内部联接

动画版

在此处输入图像描述

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

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

内部 2

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

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

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

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

洛杰

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

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

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

loj 为空

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

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

罗杰

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

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

FOJ

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

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

FOJ 2

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

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

联合所有

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

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

洛杰

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

LOJ到内

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

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

在此处输入图像描述

SQL小提琴

查看这些示例在 SQLFiddle.com 上实时运行

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

员工

企业标识 企业名称
13 杰森
8 亚历克斯
3 内存
17 巴布
25 约翰逊

地点

企业标识 EmpLoc
13 圣荷西
8 洛杉矶
3 印度浦那
17 印度钦奈
39 印度班加罗尔

内连接:-内连接通过基于连接谓词组合两个表(员工位置)的列值来创建一个新的结果表。 该查询将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 的结果如下所示:

员工.EmpId 员工.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣荷西
8 亚历克斯 8 洛杉矶
3 内存 3 印度浦那
17 巴布 17 印度钦奈

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

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

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

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

员工.EmpId 员工.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣荷西
8 亚历克斯 8 洛杉矶
3 内存 3 印度浦那
17 巴布 17 印度钦奈
25 约翰逊 无效的 无效的

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

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

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

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

员工.EmpId 员工.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣荷西
8 亚历克斯 8 洛杉矶
3 内存 3 印度浦那
17 巴布 17 印度钦奈
无效的 无效的 39 印度班加罗尔

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

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

员工.EmpId 员工.EmpName 位置.EmpId 位置.EmpLoc
13 杰森 13 圣荷西
8 亚历克斯 8 洛杉矶
3 内存 3 印度浦那
17 巴布 17 印度钦奈
25 约翰逊 无效的 无效的
无效的 无效的 39 印度班加罗尔

MySQL 8.0 参考手册 - 连接语法

Oracle 联接操作

内部联接

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

在此处输入图像描述

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

左外连接

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

在此处输入图像描述

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

全外连接

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

在此处输入图像描述

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

参考

简单来说:

内连接只检索匹配的行。

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

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

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

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

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

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

内部联接要求联接表中存在具有相关 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 记录。

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

简单来说:

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

左连接->

伪代码

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值作为连接结果。

例子 :

例子

现在让我们假设 2 个表

1.employees , 2.phone_numbers_employees

employees : id , name 

phone_numbers_employees : id , phone_num , emp_id   

这里,employees表是主表,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;

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

图表

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

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

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

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

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

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

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

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

这是加入的很好的解释

对于所有类型的联接,这都是一个很好的图解说明

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

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

笔记 :
SQLite中没有RIGHT OUTER JOINFULL OUTER JOIN
而且在MySQL中也没有FULL OUTER JOIN

我的回答是基于上面的Note

当您有两个这样的表时:

--[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
(对于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

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

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

内部联接。

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

外连接。

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

在此处输入图像描述

  • INNER JOIN最典型的两个或多个表的连接。 它返回表 ON primarykey 和 forignkey 关系上的数据匹配。
  • 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 

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

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

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

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

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

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

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

在此处输入图像描述

INNER JOIN , LEFT/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)用于 RIGHT 外连接加入。 这是为了确保第一个表的所有行都存在于最终结果中。

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

  • ... ON T1.title = T2.title AND T1.version < T2.version (=> 将此帖子视为示例用法:仅选择列上具有最大值的行
  • ... ON T1.y IS NULL
  • ... ON 1 = 0 (就像示例一样)

内连接与左外连接


在此处输入图像描述

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

最简单的定义

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

Full Outer Join:返回两个表中匹配和不匹配的记录,对于来自Both Tables的不匹配记录返回 null。

Left Outer Join:仅从Left Side的表中返回匹配和不匹配的记录。

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

简而言之

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

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

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

匹配 =内连接

总体思路

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

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

基础

交叉连接

交叉连接

SELECT *
  FROM citizen
 CROSS JOIN postalcode

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

交叉连接结果

内部联接

INNER JOIN和简单的一样: JOIN

内部联接

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

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

内部连接结果

左外连接

LEFT OUTER JOINLEFT JOIN相同

左加入

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

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

左连接结果

播放数据

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

使用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的工作方式:

CrossJoinUnion1

试图像这样表示它:

CrossJoinUnion2Crossing

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

CrossJoinUnionUnion3

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

内部联接

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

InnerJoinIntersection - 填充

当使用带有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

自加入结果

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

外连接

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

LeftJoinIntersection - 填充

WHERE 子句 - 有意义

在月球上使用 Smith 和邮政编码从CROSS JOIN中查找所有行:

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

哪里 - 结果

现在维恩图不用于反映JOIN 用于WHERE子句:

在哪里

..这是有道理的。

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

..并给出结果:

联合 - 结果

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

联盟

不适用时

一个重要的注意事项是,这些仅在两个 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

简单来说,

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

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

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

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

5. FULL JOIN: Full Join和Full outer Join是一样的。

left join on返回行上的inner join on union allnull s 扩展的不匹配的左表行。

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

full join on返回行的inner join on union all unmatched left table rows selected by null s union all unmatched right table rows are extended by null s。

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 中的 CROSS JOIN 与 INNER JOIN

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

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

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

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

1.内连接:也称为连接。 当存在匹配时,它才会返回左表和右表中存在的行。 否则,它返回零记录。

例子:

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

输出1

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

例子:

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

输出2

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

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

加入

连接的优点

  1. 执行速度更快。

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

在此处输入图像描述

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

表 A 和表 B 由 Table_A 连接。 id = 表_B。 name_id

内部联接

在此处输入图像描述

仅显示匹配的 ID 行。

外连接

在此处输入图像描述

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

在此处输入图像描述

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

在此处输入图像描述 显示了两个表中匹配的 id 和不匹配的行。

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

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

考虑以下 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。

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

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

对于A数据子集的SELECT

  • 当您要查找的相关B数据必须在每个数据库设计中存在时,请使用INNER JOIN
  • 当您正在寻找的相关B数据可能或可能存在每个数据库设计时,请使用LEFT JOIN

还有LEFT JOINRIGHT JOINFULL JOIN配合?

一个示范

设置

跳入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 JOINOUTER JOIN都暗示OUTER

假设我们有两个表:照片和用户。 我们的目标是“显示每个照片网址和照片的用户名”。 这是查询:

SELECT url,username
FROM photos
JOIN users on users.id=photos.user_id

内部联接

它是默认连接。 它连接照片和表格并根据条件“users.id=photos.user_id”返回交集。

在此处输入图片说明

如果 photos 表中有一行user_id=Null ,则不会在查询结果中显示。

左外连接

在此处输入图片说明

如果照片表中的任何内容与用户表不匹配,我们不会将其删除。 如果该行没有匹配项,我们用Null值填充它

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

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

全连接是内连接加上左右连接。

总之,如果我们有这样的表 A

身份证 列表A 数据库
1 乔恩 1
2 莎拉 1
3 克拉克 2
4 芭比 NULL

像这样的表B:

数据库 列表B
1 康纳
2 肯特
3 斯波克

内连接:

from tableA join tableB on tableA.idB = tableB.idB
身份证 列表A 数据库 列表B
1 乔恩 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特

左外连接:

from tableA left join tableB on tableA.idB = tableB.idB
身份证 列表A 数据库 列表B
1 乔恩 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特
4 芭比 NULL NULL

右外连接:

from tableA right join tableB on tableA.idB = tableB.idB
身份证 列表A 数据库 列表B
1 乔恩 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特
NULL NULL 3 斯波克

全外连接:

from tableA full join tableB on tableA.idB = tableB.idB
身份证 列表A 数据库 列表B
1 乔恩 1 康纳
2 莎拉 1 康纳
3 克拉克 2 肯特
4 芭比 NULL NULL
NULL NULL 3 斯波克

内连接在两个或多个表中提供匹配的记录。 在 where 子句中应用任何过滤器并匹配另一张表的记录后,外连接给出一张表的所有记录。 全外连接给出了两个表中的所有记录。

表 A col1 1 2 3 4 5

表 B Col1 3 4 5 6 7

Col1 上的内连接:3 4 5

Col1 上的左外连接 B:1 2 3 4 5

Col1 上的右外连接 B:3 4 5 6 7

Col1 上的完全外连接 B:1 2 3 4 5 6 7

内连接VS。 外连接

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


内部联接

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

例子

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

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

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

 /* CSS styles */ .circles { display: flex; } .circle { height: 100px; width: 100px; border-radius: 50%; background: #99AEBA; } .circle:first-child { background: #FF0000; } .circle:nth-child(2) { background: #05E156; transform: translateX(-45px); z-index: 2; mix-blend-mode: multiply; }
 <!DOCTYPE html> <html> <head> <title>INNER JOIN</title> </head> <body> <div class="circles"> <div class="circle"></div> <div class="circle"></div> </div> </body> </html>

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

价格 数量
P.产品 P.价格 Q.产品 Q.数量
一个 6€ 一个 92
5€ 27
C 5€ D 66
D 1€ 20

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

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

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

产品 价格 数量
一个 6€ 92
5€ 27
D 1€ 66

外连接

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

外连接分为三种类型:

  • LEFT OUTER JOIN连接(或左连接)
  • RIGHT OUTER JOIN连接(或右连接)
  • FULL OUTER JOIN (或完全连接)

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

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

我的消息来源:

我想告诉您,当您想要连接以提高性能时,您必须使用索引列。

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

SELECT Sname, Tname FROM student s JOIN teacher t ON s.id = t.id;

在这种情况下,如果您还想从不同的表中获取其他数据信息,我们可以使用 go 进行外连接

我们有 3 种类型的外部连接:

左连接、右连接和完全连接

我们还将为LEFT OUTER JOIN 从左(第一个)表中检索不相关的数据。

SELECT Sname, Tname FROM student s LEFT JOIN teacher t ON s.id = t.id;

RIGHT OUTER JOIN ,我们还从右表(第二个表)中检索不相关的数据

SELECT Sname, Tname FROM student s RIGHT JOIN teacher t ON s.id = t.id;

当我们想从两个表中检索所有/完整数据时,我们可以使用FULL OUTER JOIN ,缺失的数据将用 NULL 填充。

SELECT Sname, Tname FROM student s FULL JOIN teacher t ON s.id = t.id;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM