5042

又如何LEFT JOINRIGHT JOIN又如何FULL JOIN适应?

4

27 回答 27

6510

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

  • 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
于 2008-09-01T22:59:34.840 回答
871

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

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

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

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

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

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

在此处输入图像描述


解释

源表

在此处输入链接描述

首先从CROSS JOIN(AKA 笛卡尔积)开始。这没有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. 在这种特殊情况下,这些将是保留的行,因为它们在右侧 table 中没有匹配,并且查询返回 table 中不匹配的单个红色行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 上实时运行

于 2014-12-13T11:58:59.393 回答
233

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

于 2014-12-18T06:54:55.213 回答
168

内部联接

仅检索匹配的行,即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

参考

于 2014-01-27T12:16:05.317 回答
127

简单来说:

连接只检索匹配的行。

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

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

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

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

于 2013-01-12T11:07:41.150 回答
119

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

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

于 2008-09-01T22:38:43.643 回答
96

内部联接要求联接表中存在具有相关 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 子句WHERE OrderDetails.OrderID IS NULL

于 2008-09-01T22:47:39.020 回答
81

简单来说:

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

左连接->

伪代码

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 表是 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;

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

图表

于 2015-02-19T04:50:21.217 回答
65

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

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

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

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

于 2012-09-27T07:33:12.490 回答
63

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

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

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

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

于 2010-09-02T09:49:28.913 回答
53

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

注意:里面没有or
。 而且里面也没有。SQLiteRIGHT OUTER JOINFULL OUTER JOIN
MySQLFULL OUTER JOIN

我的回答是基于上面的Note

当您有两个这样的表时:

--[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

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

于 2015-04-13T13:07:50.730 回答
42

内部联接。

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

外连接。

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

于 2014-04-11T09:18:07.163 回答
34

在此处输入图像描述

  • INNER JOIN两个或多个表的最典型连接。它返回表 ON primarykey 和 forignkey 关系上的数据匹配。
  • OUTER JOIN与 相同INNER JOIN,但它还包括NULLResultSet 上的数据。
    • LEFT JOIN= INNER JOIN+表不匹配数据与Null右表匹配。
    • RIGHT JOIN= INNER JOIN+表不匹配的数据与Null左表匹配。
    • FULL JOIN= +右表和左INNER JOIN上的不匹配数据都匹配。Null
  • 自联接不是 SQL 中的关键字,当表本身引用数据时称为自联接。使用INNER JOINandOUTER 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 
于 2017-12-26T16:49:13.737 回答
33

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

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

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

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

于 2013-11-17T12:59:46.530 回答
31

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

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

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

在此处输入图像描述

于 2016-01-22T15:23:20.503 回答
30

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(就像样本一样)

内连接与左外连接


在此处输入图像描述

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

于 2016-11-08T12:25:02.977 回答
25

最简单的定义

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

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

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

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

简而言之

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

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

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

匹配 =内连接

于 2016-04-28T09:10:48.903 回答
15

总体思路

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

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

基础

交叉连接

交叉连接

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 JOIN是相同的LEFT JOIN

左加入

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

结果将是所有内容,citizen即使 中没有匹配项postalcode。再次需要一个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;

玩时边界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来获得 a 的结果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来获得 a 的结果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表格)。

交叉连接

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

行是不同的。总共是 7行UNION。但是它们对于一个共同的SQL结果集是不兼容的。这根本不是 a 的CROSS JOIN工作方式:

CrossJoinUnion1

试图像这样表示它:

CrossJoinUnion2Crossing

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

CrossJoinUnionUnion3

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

内部联接

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

InnerJoinIntersection - 填充

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

使用 self- JOIN,这些行实际上是两个表中的相同元素,但是将表表示为两者A并且B不是很合适。例如JOIN,使元素 in与B 中的不同A元素匹配的常见自条件是,在单独的元素上匹配 from到。从这样的例子中:ON A.parent = B.childABSQL

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

自加入结果

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

外连接

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

LeftJoinIntersection - 填充

WHERE 子句 - 有意义

CROSS JOIN从 a with Smith 和月球上的邮政编码中查找所有行:

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

哪里 - 结果

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

在哪里

..这是有道理的。

当 INTERSECT 和 UNION 有意义时

相交

正如解释的那样, anINNER JOIN并不是真正的INTERSECT. 但是INTERSECTs 可以用于单独查询的结果。这里的维恩图很有意义,因为来自单独查询的元素实际上是属于一个结果或两者的行。相交显然只会返回两个查询中都存在该行的结果。这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,导致返回结合两个SELECTs 的所有结果:

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

于 2020-05-06T23:26:39.260 回答
14

简单来说,

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

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

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

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

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

于 2016-10-13T08:53:11.007 回答
9

关于这个主题有很多错误信息,包括 Stack Overflow 上的这里。

left join on(aka left outer join on) 返回由s扩展的不匹配的左表行inner join onunion allnull

right join (onaka right outer join on) 返回由s扩展的不匹配的右表行inner join onunion allnull

full join on(aka full outer join on) 返回由 s 扩展的不匹配的左表行 由 s 扩展inner join on的不匹配的右表行。union allnullunion allnull

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

因此,outer join在您知道所inner join涉及的基础是什么之前,请不要这样做。


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

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

于 2017-09-07T08:35:16.250 回答
5
  • 内连接-使用任一等效查询的内连接给出了两个表的交集它们共有的两行。

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

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

于 2016-02-02T11:43:28.297 回答
5

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. 执行速度更快。
于 2017-07-10T11:56:47.090 回答
4

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

在此处输入图像描述

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

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

内部联接

在此处输入图像描述

仅显示匹配的 ID 行。

外连接

在此处输入图像描述

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

在此处输入图像描述

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

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

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

于 2020-07-31T10:45:03.797 回答
3

inner join和的区别outer join如下:

  1. Inner join是基于匹配元组组合表outer join的连接,而是基于匹配和不匹配元组组合表的连接。
  2. Inner join合并两个表中的匹配行,其中不匹配的行被省略,而outer join合并两个表中的行,不匹配的行填充空值。
  3. Inner join类似于交集运算,而outer join类似于联合运算。
  4. Inner join是两种类型,而outer join是三种类型。
  5. outer join比 快inner join
于 2017-10-17T12:25:56.637 回答
3

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

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

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

左连接:

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

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

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

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

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

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

也可以在这里查看 DEMO 。

于 2018-11-25T14:50:41.483 回答
3

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

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

对于一个数据SELECT子集A

  • INNER JOIN当您要查找的相关B数据必须在每个数据库设计中存在时使用;
  • 当您正在寻找LEFT JOIN的相关数据可能或可能存在每个数据库设计时使用。B
于 2019-10-25T17:22:43.203 回答
1

一个示范

设置

进入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;

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

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

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

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

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

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

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

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

内部与外部

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

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

  • JOIN本身就意味着INNER
  • LEFT JOIN,RIGHT JOIN并且OUTER JOIN都暗示OUTER
于 2021-04-23T19:38:42.933 回答