提问人:Chris de Vries 提问时间:9/2/2008 最后编辑:SuperStormerChris de Vries 更新时间:10/4/2022 访问量:2606779
“INNER JOIN”和“OUTER JOIN”有什么区别?
What is the difference between "INNER JOIN" and "OUTER JOIN"?
答:
仅当联接的另一侧(右侧)有匹配的记录时,内部联接才会显示行。
(左侧)外部联接在左侧显示每条记录的行,即使联接的另一侧(右侧)没有匹配的行也是如此。如果没有匹配的行,则另一侧(右侧)的列将显示 NULL。
内部联接要求联接表中存在具有相关 ID 的记录。
外部联接将返回左侧的记录,即使右侧不存在任何记录。
例如,您有一个 Orders 和一个 OrderDetails 表。它们通过“OrderID”关联。
订单
- 订单 ID
- 客户名称
订单详情
- 订单详细信息 ID
- 订单 ID
- 产品名称
- 数量
- 价格
请求
SELECT Orders.OrderID, Orders.CustomerName
FROM Orders
INNER JOIN OrderDetails
ON Orders.OrderID = OrderDetails.OrderID
将仅返回 OrderDetails 表中也有内容的 Orders。
如果将其更改为 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
评论
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
假设您正在联接没有重复项的列,这是一个非常常见的情况:
例子
假设您有两个表,每个表有一列,数据如下所示:
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 部分为 null,反之亦然。
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
评论
INNER JOIN
要求在比较两个表时至少匹配。例如,表 A 和表 B 表示 A ٨ B(A 交集 B)。
LEFT OUTER JOIN
并且是一样的。它给出了两个表中的所有匹配记录以及左侧表的所有可能性。LEFT JOIN
同样,并且是相同的。它给出了两个表中的所有匹配记录以及正确表的所有可能性。RIGHT OUTER JOIN
RIGHT JOIN
FULL JOIN
是重复和不重复的组合。LEFT OUTER JOIN
RIGHT OUTER JOIN
使用 INNER JOIN
返回两个表中存在匹配项的所有行。即在结果表中,所有行和列都将具有值。
在 OUTER JOIN
中,生成的表可能具有空列。外部连接可以是 或 。LEFT
RIGHT
LEFT OUTER JOIN
返回第一个表中的所有行,即使第二个表中没有匹配项也是如此。
RIGHT OUTER JOIN
返回第二个表中的所有行,即使第一个表中没有匹配项也是如此。
简单来说:
内部联接仅检索匹配的行。
而外部联接从一个表中检索匹配的行,并在另一个表中检索所有行。结果取决于您使用的是哪一个:
左:右表中的匹配行和左表中的所有行
右:左表中的匹配行和右表中的所有行,或者
完整:所有表中的所有行。有没有匹配并不重要
评论
我在其他答案中没有看到有关性能和优化器的太多细节。
有时很高兴知道 only 是关联的,这意味着优化器有最多的选择来使用它。它可以对联接顺序进行重新排序,使其更快,保持相同的结果。优化器可以使用最多的联接模式。INNER JOIN
通常,尝试使用不同类型的联接来代替是一种很好的做法。(当然,如果可能的话,请考虑预期的结果集。INNER JOIN
关于这种奇怪的联想行为,这里有几个很好的例子和解释:
评论
INNER JOIN
LEFT JOIN
LEFT JOIN
INNER JOIN
WHERE
NULL
内部连接
仅检索匹配的行,即 .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
引用
评论
内部联接。
联接是合并两个表中的行。内部联接会尝试根据您在查询中指定的条件匹配两个表,并且仅返回匹配的行。如果联接中第一个表中的行与第二个表中的两行匹配,则结果中将返回两行。如果第一个表中的行与第二个表中的行不匹配,则不会返回该行;同样,如果第二个表中的行与第一个表中的行不匹配,则不会返回该行。
外部连接。
左联接尝试查找第一个表中的行与第二个表中的行的匹配项。如果找不到匹配项,它将返回第一个表中的列,并将第二个表中的列留空 (null)。
维恩图并不能真正为我做到这一点。
例如,它们没有显示交叉连接和内部连接之间的任何区别,或者更一般地显示不同类型的连接谓词之间的任何区别,或者提供一个框架来推理它们将如何操作。
理解逻辑处理是无可替代的,无论如何,它相对容易掌握。
- 想象一个交叉连接。
- 针对步骤 1 中的所有行计算子句,将谓词计算为
on
true
- (仅适用于外部联接)重新添加在步骤 2 中丢失的任何外部行。
(注意:在实践中,查询优化器可能会找到比上述纯逻辑描述更有效的查询执行方法,但最终结果必须相同)
我将从一个完整的外部连接的动画版本开始。进一步的解释如下。
解释
源表
首先从一个(又名笛卡尔积)开始。它没有子句,只是返回两个表中的每个行组合。CROSS JOIN
ON
从交叉连接 B 中选择 A.Colour、B.Colour
内部连接和外部连接具有“ON”子句谓词。
- 内部连接。计算交叉联接结果中所有行的“ON”子句中的条件。如果为 true,则返回联接行。否则丢弃它。
- 左外连接。与内部联接相同,然后对于左表中与任何内容不匹配的任何行,输出这些行,右表列的 NULL 值为空。
- 右外连接。与内部联接相同,然后对于右表中与任何内容不匹配的任何行,输出这些行,左表列的 NULL 值。
- 完全外部连接。与内部连接相同,然后保留左外连接中的左不匹配行,并保留右外连接中的右不匹配行。
一些例子
SELECT A.Colour, B.Colour FROM A INNER JOIN B ON A.Colour = B.Colour
以上是经典的 equi join。
动画版
选择 A.Colour, B.Colour FROM A INNER JOIN B ON A.Colour NOT IN ('Green', 'Blue')
内部联接条件不一定是相等条件,也不需要引用两个表(甚至两个表之一)中的列。对交叉联接的每一行进行计算将返回。A.Colour NOT IN ('Green','Blue')
选择 A.Colour, B.Colour FROM A INNER JOIN B ON 1 =1
对于交叉联接结果中的所有行,联接条件的计算结果为 true,因此这与交叉联接相同。我不会再重复 16 行的图片了。
选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour
外部联接的逻辑计算方式与内部联接相同,不同之处在于,如果左表中的一行(对于左联接)根本没有与右表中的任何行联接,则该行将保留在结果中,并保留右侧列的值。NULL
选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour IS NULL
这只会将上一个结果限制为仅返回其中 .在这种特殊情况下,这些将是保留的行,因为它们在右侧表中没有匹配项,并且查询返回表中不匹配的单个红色行。这被称为反半挂接。B.Colour IS NULL
B
请务必为测试选择一个不可为 null 的列,或者联接条件确保排除任何值的列,以便此模式正常工作,并避免只带回恰好具有该列值的行以及不匹配的行。IS NULL
NULL
NULL
选择 A.Colour, B.Colour FROM A RIGHT OUTER JOIN B ON A.Colour = B.Colour
右外联接的作用与左外联接类似,只是它们保留右表中的不匹配行,而 null 扩展左列。
选择 A.Colour, B.Colour FROM A FULL OUTER JOIN B ON A.Colour = B.Colour
完全外部连接结合了左连接和右连接的行为,并保留了左表和右表中的不匹配行。
选择 A.Colour, B.Colour FROM A FULL OUTER JOIN B ON 1 = 0
交叉联接中没有与谓词匹配的行。两端的所有行都使用常规的外部联接规则进行保留,另一端表中的列中为 NULL。1=0
选择 COALESCE(A.Colour, B.Colour) 作为颜色 从完全外部连接 B 上 1 = 0
通过对前面的查询进行小幅修改,可以模拟两个表中的一个。UNION ALL
选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour = 'Green'
请注意,该子句(如果存在)在逻辑上在联接后运行。一个常见的错误是执行左外联接,然后在右表上包含一个 WHERE 子句,该子句带有条件,最终排除不匹配的行。以上内容最终执行了外部连接...WHERE
...然后运行“Where”子句。 计算结果不为 true,因此外部连接保留的行最终被丢弃(与蓝色连接一起),有效地将连接转换回内部连接。NULL= 'Green'
如果意图仅包括 B 中颜色为绿色的行和 A 中的所有行,则无论正确的语法为
选择 A.Colour, B.Colour FROM A LEFT OUTER JOIN B ON A.Colour = B.Colour AND B.Colour = 'Green'
SQL 小提琴
请参阅这些在 SQLFiddle.com 上实时运行的示例。
评论
联接用于合并两个表中的数据,结果是一个新的临时表。联接是基于称为谓词的东西执行的,谓词指定执行联接时要使用的条件。内部联接和外部联接之间的区别在于,内部联接将仅返回基于联接谓词实际匹配的行。 例如,让我们考虑 Employee 和 Location 表:
员工
EmpID | EmpName(英语:EmpName) |
---|---|
13 | 杰森 |
8 | 亚历克斯 |
3 | 公羊 |
17 | 先生 |
25 | 约翰生 |
位置
EmpID | EmpLoc (英语) |
---|---|
13 | 圣何塞 |
8 | 洛杉矶 |
3 | 印度浦那 |
17 | Chennai, 印度 |
39 | 印度班加罗尔 |
内部连接:-内部联接通过基于联接谓词组合两个表(Employee 和 Location)的列值来创建新的结果表。该查询将 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 | 位置.EmpId | 位置.EmpLoc |
---|---|---|---|
13 | 杰森 | 13 | 圣何塞 |
8 | 亚历克斯 | 8 | 洛杉矶 |
3 | 公羊 | 3 | 印度浦那 |
17 | 先生 | 17 | Chennai, 印度 |
外接头:-外部联接不要求两个联接表中的每条记录都具有匹配的记录。联接表将保留每条记录,即使不存在其他匹配记录也是如此。外联接进一步细分为左外联接和右外联接,具体取决于保留的表行(左行或右行)。
左外连接:-表 Employee 和 Location 的左外联接(或简称为左联接)的结果始终包含“左”表 (Employee) 的所有记录,即使联接条件在“右”表 (Location) 中找不到任何匹配的记录也是如此。 下面是左外联接的 SQL 的样子,使用上表:
select * from employee left outer join location on employee.empID = location.empID;
//Use of outer keyword is optional
现在,运行此 SQL 的结果如下所示:
Employee.EmpId | Employee.EmpName | 位置.EmpId | 位置.EmpLoc |
---|---|---|---|
13 | 杰森 | 13 | 圣何塞 |
8 | 亚历克斯 | 8 | 洛杉矶 |
3 | 公羊 | 3 | 印度浦那 |
17 | 先生 | 17 | Chennai, 印度 |
25 | 约翰生 | 零 | 零 |
请注意,虽然 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 | 位置.EmpId | 位置.EmpLoc |
---|---|---|---|
13 | 杰森 | 13 | 圣何塞 |
8 | 亚历克斯 | 8 | 洛杉矶 |
3 | 公羊 | 3 | 印度浦那 |
17 | 先生 | 17 | Chennai, 印度 |
零 | 零 | 39 | 印度班加罗尔 |
请注意,虽然没有员工被列为在班加罗尔工作,但它仍然包含在结果中,而员工字段被清空。
全外联结:-完全外部连接或完全连接是通过在连接结果中包含不匹配的行来保留不匹配的信息,使用完全外部连接。它包括两个表中的所有行,而不管另一个表是否具有匹配的值。
Employee.EmpId | Employee.EmpName | 位置.EmpId | 位置.EmpLoc |
---|---|---|---|
13 | 杰森 | 13 | 圣何塞 |
8 | 亚历克斯 | 8 | 洛杉矶 |
3 | 公羊 | 3 | 印度浦那 |
17 | 先生 | 17 | Chennai, 印度 |
25 | 约翰生 | 零 | 零 |
零 | 零 | 39 | 印度班加罗尔 |
评论
简单来说:
内部联接 -> 仅从父表和子表中获取公共记录,其中父表的主键与子表中的外键匹配。
左联接 ->
伪代码
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.
}
}
右连接:与左连接正好相反。将表名放在右侧的 LEFT JOIN 中,您将获得与 LEFT JOIN 相同的输出。
外部连接:显示两个表中的所有记录。如果左表中的记录与基于主键的右表不匹配,则使用空值作为连接的结果。No matter what
例:
现在让我们假设 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;
从图解上看,它看起来像:
评论
答案在于每一个的含义,所以在结果中。
注意:
中没有或。
而且没有.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
,
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 [OUTER] JOIN :
当您想在上述结果中拥有其中一个表的所有行时 - 具有相同的关系 - 您可以使用:
(对于RIGHT JOIN,只需更改表的位置)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 :
当您还希望在结果中包含其他表的所有行时,可以使用: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
评论
TableA a LEFT OUTER JOIN TableB b
TableB B RIGHT OUTER JOIN TableA a
内部联接 - 使用任一等效查询的内部联接给出两个表的交集,即它们共有的两行。
左外联接 - 左外联接将给出 A 中的所有行,以及 B 中的任何公共行。
完全外连接 - 完全外部连接将为您提供 A 和 B 的并集,即 A 中的所有行和 B 中的所有行。如果 A 中的某些东西在 B 中没有相应的基准面,则 B 部分为 null,反之亦然
评论
Join is not an intersection unless the tables have the same columns
最简单的定义
内部联接:从两个表中返回匹配的记录。
完全外部联接:返回两个表中的匹配和不匹配的记录,两个表中的不匹配记录为 null。
左外联接:仅从左侧表中返回匹配和不匹配的记录。
右外联接:仅从右侧的表中返回匹配和不匹配的记录。
简而言之
匹配 + 左不匹配 + 右不匹配 = 完全外部连接
匹配 + 左不匹配 = 左外连接
匹配 + 右不匹配 = 右外连接
匹配 = 内部联接
评论
简单来说,
1.INNER JOIN OR EQUI JOIN :返回仅与两个表中的条件匹配的结果集。
2.OUTER JOIN :返回两个表中所有值的结果集,即使条件是否匹配。
3.LEFT JOIN:返回左表中所有值的结果集,仅返回与右表中的条件匹配的行的结果集。
4.RIGHT JOIN:返回右表中所有值的结果集,仅返回与左表中的条件匹配的行。
5.FULL JOIN:Full Join和Full outer Join相同。
的精确算法如下:INNER JOIN
LEFT/RIGHT OUTER JOIN
- 从第一个表中获取每一行:
a
- 考虑它旁边的第二个表中的所有行:
(a, b[i])
- 针对每对评估子句:
ON ...
ON( a, b[i] ) = true/false?
- 当条件的计算结果为 时,返回组合行。
true
(a, b[i])
- 当到达第二个表的末尾而没有任何匹配时,这是一个(虚拟)对,用于其他表的所有列:用于 LEFT 外连接或用于 RIGHT 外部连接。这是为了确保第一个表的所有行都存在于最终结果中。
Outer Join
Null
(a, Null)
(Null, b)
- 当条件的计算结果为 时,返回组合行。
注意:子句中指定的条件可以是任何内容,不需要使用主键(并且您不需要总是引用两个表中的列)!例如:ON
... ON T1.title = T2.title AND T1.version < T2.version
( => 将这篇文章视为示例用法:仅选择列上具有最大值的行)... ON T1.y IS NULL
... ON 1 = 0
(仅作为示例)
注意:左连接 = 左外连接,右连接 = 右外连接。
评论
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
2.全外联接:又称全联接。它返回左表和右表中存在的所有行。
例:
SELECT
e1.emp_name,
e2.emp_salary
FROM emp1 e1
FULL OUTER JOIN emp2 e2
ON e1.emp_id = e2.emp_id
3.左外连接:或简称为左连接。它返回左表中存在的所有行以及右表中的匹配行(如果有)。
4.右外连接:也称为右连接。它返回左表中的匹配行(如果有),以及右表中存在的所有行。
联接的优点
- 执行速度更快。
left join on
返回 Rows 与 S 扩展的左侧表行不匹配。inner join on
union all
null
right join on
返回行 不匹配的右表行扩展了 s。inner join on
union all
null
full join on
返回行 不匹配的左表行 扩展 S 不匹配的右表行 扩展 S 的行。inner join on
union all
null
union all
null
outer
是可选的,没有效果。
(SQL Standard 2006 SQL/Foundation 7.7 语法规则 1、一般规则 1 b、3 c 和 d、5 b.)
因此,在您知道涉及什么底层之前,不要这样做。outer join on
inner join on
找出返回的行:SQL 中的 CROSS JOIN 与 INNER JOINinner join on
这也解释了为什么维恩图对内部连接与外部连接没有帮助。 有关为什么它们通常对连接没有帮助的更多信息:自然连接的维恩图
评论
和的区别如下:inner join
outer join
Inner join
是基于匹配元组组合表的联接,而是基于匹配和不匹配元组组合表的联接。outer join
Inner join
合并两个表中的匹配行,其中省略了不匹配的行,而合并两个表中的行和不匹配的行填充 null 值。outer join
Inner join
类似于交叉操作,而类似于联合操作。outer join
Inner join
是两种类型,而是三种类型。outer join
outer join
比 快。inner join
评论
INNER JOIN
两个或多个表的最典型联接。 它返回表 ON 主键和 forignkey 关系的数据匹配。OUTER JOIN
与 相同,但它也包括 ResultSet 上的数据。INNER JOIN
NULL
LEFT JOIN
=INNER JOIN
+ 左表的数据与右表的匹配数据不匹配。Null
RIGHT JOIN
=INNER JOIN
+ 右表的数据与左表的匹配数据不匹配。Null
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
请考虑以下 2 个表:
DM1型
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
如上所述,不是从输出中的 EMP 打印的,因为它dept_id在 Department 表中找不到匹配项。同样,和行不会从 Department 表打印,因为它们在 Emp 表中找不到匹配项。Jose
6
HR
R&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
并且行不是从 Department 表打印的,因为它们在 dept_id 的 Emp 表中找不到匹配项。R&D
因此,LEFT JOIN 返回 Left 表中的所有行,并且仅返回 RIGHT 表中的匹配行。
也可以在这里查看演示。
这里有很多很好的答案,有非常准确的关系代数示例。这是一个非常简化的答案,可能对有 SQL 编码困境的业余或新手编码人员有所帮助。
基本上,查询通常归结为两种情况:JOIN
对于数据子集:SELECT
A
- 当您要查找的相关数据必须根据数据库设计存在时使用;
INNER JOIN
B
- 根据数据库设计,当您要查找的相关数据可能存在或可能不存在时使用。
LEFT JOIN
B
总体思路
请参阅 Martin Smith 的回答,以更好地说明和解释不同的连接,包括 和 之间的差异。FULL OUTER JOIN
RIGHT OUTER JOIN
LEFT 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 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
用于获取 a 的结果需要一些技巧,例如在行中添加。它被省略了。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
在这里,内部连接可以真正看作是结果与删除的条件不匹配的交叉连接。此处不会删除任何生成的行。
用于获得 a 的结果也需要技巧。它被省略了。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 outer”的图像将显示大量维恩图。我的办公桌上曾经有一份打印本。但是表示存在问题。
维恩图非常适合集合论,其中元素可以在一个或两个集合中。但是对于数据库来说,在我看来,一个“集合”中的元素似乎是表中的一行,因此在任何其他表中都不存在。多个表中没有一行这样的事情。行对于表是唯一的。
自连接是一种极端情况,其中每个元素在两个集合中实际上是相同的。但它仍然没有以下任何问题。
在下面的讨论中,集合代表左边(桌子)上的集合,集合是右边(桌子)上的集合。A
citizen
B
postalcode
交叉连接
两个集合中的每个元素都与另一个集合中的每个元素匹配,这意味着我们需要每个元素的数量和每个元素的数量来正确表示这个笛卡尔乘积。集合论不是为集合中的多个相同元素制作的,因此我发现维恩图无法正确表示它是不切实际/不可能的。这似乎根本不合适。A
B
B
A
UNION
行是不同的。总共有 7 行。但它们与通用结果集不兼容。这根本不是 a 的工作方式:UNION
SQL
CROSS JOIN
试图像这样表示它:
..但现在它看起来只是一个,当然不是。此外,实际上在两个不同的集合中的任何一个中都没有元素。但是,它看起来非常类似于类似于以下内容的可搜索结果:INTERSECTION
INTERSECTION
作为参考,可以在 Tutorialgateway 上看到一个可搜索的 s 结果。就像这个一样,是空的。CROSS JOIN
INTERSECTION
内部连接
元素的值取决于条件。在每一行对于该条件都是唯一的条件下,可以表示这一点。含义仅适用于一行。一旦表()中的一行与表()中的多行匹配,结果就会出现与以下相同的问题: 该行需要多次表示,而集合论并不是真正为此而制定的。在唯一性的条件下,该图可以工作,但请记住,该条件决定了图中元素的位置。只看条件的值,而行的其余部分只是在骑行中:JOIN
id=x
A
citizen
B
postalcode
JOIN
CROSS JOIN
JOIN
JOIN
当使用 a with a 条件使其变成 .INNER JOIN
ON 1 = 1
CROSS JOIN
使用 self- 时,行实际上是两个表中的标识元素,但将表表示为两者并不是很合适。例如,使 中的元素与 B 中的不同元素匹配的常见自条件是 ,使匹配从到到在单独的元素上。从这样的示例来看:JOIN
A
B
JOIN
A
ON A.parent = B.child
A
B
SQL
SELECT *
FROM citizen c1
JOIN citizen c2 ON c1.id = c2.leader
这意味着史密斯是格林和詹森的领袖。
外部连接
同样,当一行与另一个表中的行有多个匹配项时,麻烦就开始了。这更加复杂,因为 can be but of 与空集匹配。但是在集合论中,任何集合和空集合的并集总是正义的。空集不添加任何内容。这种表示通常只是显示所有 of 来说明无论是否存在匹配项,都会选择 中的行。然而,“匹配元素”存在与上图相同的问题。它们取决于条件。而空集似乎已经徘徊到:OUTER JOIN
C
C
LEFT OUTER JOIN
A
A
B
A
WHERE 子句 - 有意义
在月球上找到带有史密斯和邮政编码的 a 中的所有行:CROSS JOIN
SELECT *
FROM citizen c
CROSS JOIN postalcode p
WHERE c.name = 'Smith'
AND p.area = 'Moon';
现在,维恩图不用于反映 .它仅用于子句:JOIN
WHERE
..这是有道理的。
当 INTERSECT 和 UNION 有意义时
相交
如前所述,an 并不是真正的 .但是,s 可用于单独查询的结果。在这里,维恩图是有意义的,因为来自单独查询的元素实际上是只属于其中一个结果或两者兼而有之的行。显然,Intersect 只会返回两个查询中都存在该行的结果。这将导致与上面的行相同的行,并且维恩图也将是相同的: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';
联盟
an 不是 .但是,在与 相同的条件下工作,导致所有结果的返回结果结合了两个: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
通过一个示例更容易解释连接:
要模拟存储在单独表中的人员和电子邮件,
表 A 和表 B 由 Table_A.id = Table_B.name_id 连接
内部连接
仅显示匹配的 ID 行。
外部连接
将显示表 A 的匹配 ID 和不匹配的行。
将显示表 B 的匹配 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;
An 返回所有人猫对。
任何没有猫或没有人类的猫都被排除在外。INNER JOIN
human_name | cat_name
------------+-----------
Abe | Axel
Jen | Jellybean
Jen | Juniper
A 返回所有人类和所有猫,如果两边没有匹配项。FULL OUTER JOIN
NULL
human_name | cat_name
------------+-----------
Abe | Axel
Ann | [NULL]
Ben | [NULL]
Jen | Jellybean
Jen | Juniper
[NULL] | Bitty
A 返回所有人员(左表)。
任何没有猫的人都会在列中得到一个。
任何没有人类的猫都被排除在外。LEFT OUTER JOIN
NULL
cat_name
human_name | cat_name
------------+-----------
Abe | Axel
Ann | [NULL]
Ben | [NULL]
Jen | Jellybean
Jen | Juniper
A 返回所有猫(右表)。
任何没有人类的猫都会在列中。
任何没有猫的人都被排除在外。RIGHT OUTER JOIN
NULL
human_name
human_name | cat_name
------------+-----------
Abe | Axel
Jen | Jellybean
Jen | Juniper
[NULL] | Bitty
内部与外部
您可以看到,虽然 an 只获取匹配的对,但每种类型的联接都包含一些没有匹配项。INNER JOIN
OUTER
但是,实际的单词并不需要出现在查询中:INNER
OUTER
JOIN
本身意味着INNER
LEFT JOIN
,并且都暗示RIGHT JOIN
OUTER JOIN
OUTER
“外部”和“内部”只是可选元素,您只是在处理两(三)种连接。内部联接(或仅使用“联接”时的默认值)是两个表上仅存在与条件匹配的元素的联接。
“外部”联接与内部联接相同,加上左表或右表中不匹配的元素,在另一个表的所有列上添加空值。
完全连接是内部连接加上右连接和左连接。
综上所述,如果我们有这样的表 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 | 斯波克 |
上一个:清除用户密码
下一个:参数化 SQL IN 子句
评论