“INNER JOIN”和”OUTER JOIN”有什么区别?
此外怎么办LEFT JOIN
,RIGHT JOIN
和FULL JOIN
适合吗?
回答
假设您正在加入没有重复的列,这是一种非常常见的情况:
例子
假设您有两个表,每个表都有一个列,数据如下:
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
- 一个很好的解释,但是这个陈述:*A和B的外连接给出了A联合B的结果,即维恩图联合的外部部分.*没有准确地表达.除了下列之一之外,外连接将给出A交叉B的结果:全部A(左连接),全部B(右连接)或全部A和全部B(完全连接).只有这最后一个场景真的是一个联盟B.但是,一个写得很好的解释.
- 通过在表B中添加值为4的另一行来扩充示例是很好的.这将显示内部联接不必在行的相等数量上.
- 我是对的,FULL JOIN是FULL OUTER JOIN的别名,LEFT JOIN是LEFT OUTER JOIN的别名吗?
- I have downvoted this because it is wrong. Please consider removing the answer as it will mislead generations of computer science students who are fooled by the large upcote count. Venn diagrams do not explain join. The inner part of a join is not intersection.
- @Ameer,谢谢.Join不保证订单,您需要添加ORDER BY子句.
- 是非常好的解释.但是为什么在b列中值不是有序的?即它是6,5不是5,6?
- "假设你加入了没有重复的列,这是一个非常常见的情况:" - 如果不是这样的情况会有很大变化吗?
- +语法从来都不是ANSI,它是Oracle,对于使用多个表或比较的表达式而言始终不够用。ON语法为ANSI。PS与维恩图的比较用词错误。看到我对这个问题的评论。
- @HelenNeely不幸的是这个解释是错误的.只有当所有列都相同且其语言模糊时,它的子弹才是正确的.在你的评论之前看到我的评论,以及我对这个问题的评论.
- @Damian是的,OUTER JOIN和FULL OUTER JOIN等效,并且LEFT / RIGHT JOIN等效于LEFT / RIGHT OUTER JOIN,同样,INNER JOIN等效于简单JOIN
维恩图并没有真正为我做这件事.
例如,它们没有显示交叉连接和内连接之间的任何区别,或者更一般地显示不同类型的连接谓词之间的任何区别,或者提供用于推理它们将如何操作的框架.
理解逻辑处理是无可替代的,无论如何都要相对简单.
- 想象一下交叉连接.
-
on
根据步骤1中的所有行计算子句,并保留谓词计算结果true
- (仅适用于外部联接)在步骤2中丢失的任何外部行中添加回来.
(注意:在实践中,查询优化器可能会找到比上面的纯逻辑描述更有效的执行查询的方法,但最终结果必须相同)
我将从完整外连接的动画版本开始.进一步说明如下.
说明
来源表
首先从CROSS JOIN
(AKA笛卡尔积)开始.它没有ON
子句,只返回两个表中的每个行组合.
SELECT A.Colour,B.Colour from A CROSS JOIN B
内部和外部联接具有"ON"子句谓词.
- 内部联接.为交叉连接结果中的所有行评估"ON"子句中的条件.如果为true则返回连接的行.否则丢弃它.
- 左外连接.与内部联接相同,然后对于左表中与任何内容不匹配的任何行,将这些行输出为右表列的NULL值.
- 正确的外部加入.与内部联接相同,然后对于右表中任何不匹配的行,将这些行输出为左表列的NULL值.
- 完全外部加入.与内部联接相同,然后保留左侧外部联接中的左侧非匹配行,按右侧外部联接保留右侧非匹配行.
一些例子
SELECT A.Colour,B.Colour from A INNER JOIN B ON A.Colour = B.Colour
以上是经典的equi join.
动画版
SELECT 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 INNER JOIN B ON 1 = 1
对于交叉连接结果中的所有行,连接条件的计算结果为true,因此这与交叉连接相同.我不会再重复16行的图片了.
SELECT A.Colour,B.Colour from a LEFT OUTER JOIN B ON A.Colour = B.Colour
外连接的逻辑评估方式与内连接的方式相同,只是如果左表中的一行(左连接)不与右表中的任何行连接,它将保留在结果中,其NULL
值为右栏.
SELECT 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
.这被称为反半连接.
为IS NULL
测试选择一个不可为空的列或连接条件确保NULL
将排除任何值以使此模式正常工作并避免仅返回恰好具有该NULL
值的行的列非常重要.除了未匹配的行之外的列.
SELECT A.Colour,B.Colour from A ROU OUTER JOIN B ON A.Colour = B.Colour
右外连接的作用类似于左外连接,除了它们保留右表中的非匹配行,并且null扩展左手列.
选择A.Colour,B.Colour从一个完整的外部加入B A.Colour = B.Colour
完全外连接组合了左连接和右连接的行为,并保留左表和右表的不匹配行.
选择A.Colour,B.Colour FROM A FULL OUTER JOIN B ON 1 = 0
交叉连接中的任何行都不匹配1=0
谓词.使用常规外部联接规则保留两侧的所有行,并在另一侧的表中使用NULL.
SELECT COALESCE(A.Colour,B.Colour)AS颜色来自一个完整的外部连接B ON 1 = 0
通过对前面的查询的一个小修改,可以模拟UNION ALL
两个表中的一个.
SELECT A.Colour,B.Colour from a LEFT OUTER JOIN B ON A.Colour = B.Colour WHERE B.Colour ='Green'
请注意,该WHERE
子句(如果存在)在连接后逻辑运行.一个常见错误是执行左外连接,然后包含WHERE子句,右子表上的条件最终排除不匹配的行.以上结果执行外连接...
......然后"Where"子句运行.NULL= 'Green'
不评估为true,因此外部联接保留的行最终被丢弃(与蓝色一起),有效地将联接转换回内部联接.
如果打算只包含B中的行,其中Color为绿色,而所有来自A的行都不包括正确的语法
SELECT A.Colour,B.Colour from a LEFT OUTER JOIN B ON A.Colour = B.Colour AND B.Colour ='Green'
SQL小提琴
请参阅SQLFiddle.com上的这些示例.
- 我会说虽然这对我来说几乎和维恩图一样不合适,但我欣赏人们的不同和学习方式不同,这是一个非常好的解释,不像我以前见过的,所以我支持@ypercube in奖励积分.同样很好的工作解释了在JOIN子句和WHERE子句中放置附加条件的区别.感谢你,马丁史密斯.
- @OldPro我认为维恩图是可以的,但他们对如何表示交叉连接或区分一种连接谓词(如equi join)与另一种连接谓词保持沉默.在交叉连接结果的每一行上评估连接谓词的心智模型,然后如果外部连接最后评估哪个更适合我,则添加回不匹配的行.
- 维恩图表适用于表示联盟和交叉点和差异但不能加入.对于非常简单的连接,它们具有一些较小的教育价值,即连接条件在唯一列上的连接.
- @Arth - 没错,你错了.SQL Fiddle http://sqlfiddle.com/#!3/9eecb7db59d16c80417c72d1/5155这是维恩图无法说明的.
- @MartinSmith哇,我同意,我完全错了!太习惯与一对一工作..感谢纠正.
- 你是怎么做这些动画的?很好的答案,我唯一不喜欢的是你谦虚地说维恩图不会为你做.现实情况是,它们不足以模拟正在发生的事情,这一点很重要,以免人们弄错了想法.
- @luk2302 - 是的,您需要半连接。虽然 SQL 中没有半连接关键字。相反,您可以使用 `in` 或 `exists`。即`SELECT A.Colour FROM A WHERE A.Colour IN (SELECT B.Colour FROM B)` 或者`SELECT A.Colour FROM A WHERE EXISTS (SELECT * FROM B WHERE A.Colour = B.Colour)`
- 谢谢,我已经最终使用`where exists`并且它有效.但我希望通过定期加入可以实现这一目标.不管怎么说,还是要谢谢你!顺便说一下:连接的代表性远远超过维恩图:)
连接用于组合来自两个表的数据,结果是一个新的临时表.连接是基于称为谓词的东西执行的,谓词指定了用于执行连接的条件.内连接和外连接之间的区别在于内连接将仅返回基于连接谓词实际匹配的行.让我们考虑员工和位置表:
内连接: -
内连接通过基于连接谓词组合两个表( Employee和 Location)的列值来创建新的结果表.该查询将 Employee的每一行与 Location的每一行进行比较,以查找满足join-predicate的所有行对.当通过匹配非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和 Location始终包含"左"表( Employee)的所有记录,即使连接条件未找到任何匹配的记录"右"表(位置).以下是使用上表的左外连接的SQL的样子:
select * from employee left outer join location on employee.empID = location.empID;
//Use of outer keyword is optional
现在,运行此SQL的结果如下:
右外连接: -
右外连接(或右连接)非常类似于左外连接,除非对表的处理相反."右"表(位置)中的每一行将至少出现在连接表中一次.如果从"左"表(不匹配的行员工)存在,NULL就会出现在列的员工对于那些在没有匹配的记录位置.这就是SQL的样子:
select * from employee right outer join location on employee.empID = location.empID;
//Use of outer keyword is optional
使用上面的表格,我们可以显示右外连接的结果集是什么样的:
完全外部联接: -
完全外部联接或完全联接是通过在联接的结果中包含不匹配的行来保留不匹配的信息,使用完整的外部联接.它包括来自两个表的所有行,无论另一个表是否具有匹配值.
图像来源
MySQL 8.0参考手册 - 加入语法
Oracle Join操作
- best answer so far, alternative syntax - that's what I've been looking for, thanks!
内部联接
仅检索匹配的行,即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
参考
- 工具的名称是什么?我发现它很有趣,因为它显示了行数和维恩图
- @GrijeshChauhan是的但你可以试着用[wine](http://www.winehq.org/)来运行它.
- 喔!是的我..我使用SQLyog使用葡萄酒..还有[PlayOnLinux](http://www.playonlinux.com/en/)
简单来说:
一个内部联接仅检索匹配的行.
而一个外连接检索一个表匹配的行和其他表中的所有行....结果取决于你使用哪一种:
如果在连接的另一侧(右侧)存在匹配记录,则内部联接仅显示行.
(左)外连接显示左侧每条记录的行,即使连接的另一侧(右侧)没有匹配的行.如果没有匹配的行,则另一侧(右侧)的列将显示NULL.
内部联接要求联接表中存在具有相关ID的记录.
即使右侧没有任何内容,外部联接也将返回左侧的记录.
例如,您有一个Orders和一个OrderDetails表.它们与"OrderID"相关联.
命令
- 订单ID
- 顾客姓名
订单详细信息
- OrderDetailID
- 订单ID
- 产品名称
- 数量
- 价钱
请求
SELECT Orders.OrderID, Orders.CustomerName
FROM Orders
INNER JOIN OrderDetails
ON Orders.OrderID = OrderDetails.OrderID
只会返回OrderDetails表中也有内容的订单.
如果您将其更改为OUTER LEFT JOIN
SELECT Orders.OrderID, Orders.CustomerName
FROM Orders
LEFT JOIN OrderDetails
ON Orders.OrderID = OrderDetails.OrderID
然后它将从Orders表返回记录,即使它们没有OrderDetails记录.
您可以使用此命令通过添加where子句来查找没有任何指示可能的孤立订单的OrderDetails的订单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.
}
}
右连接:与左连接完全相反.将表的名称放在右连接中右侧的LEFT JOIN中,得到与LEFT JOIN相同的输出.
外连接:显示两个表中的所有记录No matter what
.如果Left表中的记录与Primary,Forieign键的右表不匹配,则使用NULL值作为join的结果.
示例:
让我们假设现在有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
所以其子表的外键.)
内联合
仅记入2个表的记录如果employees表的主键(其id)与Child表phone_numbers_employees(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;
从图形上看,它看起来像:
- 结果与主键/唯一键/候选键和外键无关(本身)。可以并且应该不对它们进行描述。计算交叉联接,然后滤除不符合“打开”条件的行;此外,对于外部联接,已过滤/不匹配的行将扩展为NULL(按LEFT / RIGHT / FULL并包含在内)。
这是所有类型连接的一个很好的图解说明
来源:http://ssiddique.info/understanding-sql-joins-in-easy-way.html
您可以使用INNER JOIN
从两个匹配的表中返回所有行.即在结果表中,所有行和列都将具有值.
在OUTER JOIN
结果表中可能有空列.外连接可以是LEFT
或RIGHT
.
LEFT OUTER JOIN
返回第一个表中的所有行,即使第二个表中没有匹配项也是如此.
RIGHT OUTER JOIN
返回第二个表中的所有行,即使第一个表中没有匹配项也是如此.
INNER JOIN
要求在比较两个表时至少存在匹配.例如,表A和表B表示A 8 B(A交点B).
LEFT OUTER JOIN
并且LEFT JOIN
是一样的.它给出了两个表中匹配的所有记录以及左表的所有可能性.
同样,RIGHT OUTER JOIN
和RIGHT JOIN
是相同的.它给出了两个表中匹配的所有记录以及右表的所有可能性.
FULL JOIN
是复制LEFT OUTER JOIN
和RIGHT OUTER JOIN
不复制的组合.
答案是每个人的意思,所以在结果中.
我的回答是基于上面的注释.
如果有两个这样的表:
--[table1] --[table2]
id | name id | name
---+------- ---+-------
1 | a1 1 | a2
2 | b1 3 | b2
CROSS JOIN/OUTER JOIN:
您可以将所有与这些表中的数据CROSS JOIN
或只是,
这样的:
SELECT * FROM table1, table2
--[OR]
SELECT * FROM table1 CROSS JOIN table2
--[Results:]
id | name | id | name
---+------+----+------
1 | a1 | 1 | a2
1 | a1 | 3 | b2
2 | b1 | 1 | a2
2 | b1 | 3 | b2
INNER JOIN:
当您想要根据table1.id = table2.id
您可以使用的关系向上述结果添加过滤器时INNER JOIN
:
SELECT * FROM table1, table2 WHERE table1.id = table2.id
--[OR]
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id
--[Results:]
id | name | id | name
---+------+----+------
1 | a1 | 1 | a2
LEFT [OUTER] JOIN:
如果你想在上面的结果中使用其中一个表的所有行 - 具有相同的关系 - 你可以使用LEFT JOIN
🙁
对于RIGHT JOIN只需更改表的位置)
SELECT * FROM table1, table2 WHERE table1.id = table2.id
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
--[OR]
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
--[Results:]
id | name | id | name
---+------+------+------
1 | a1 | 1 | a2
2 | b1 | Null | Null
FULL OUTER JOIN:
如果您还希望在结果中包含其他表的所有行,则可以使用FULL OUTER JOIN
:
SELECT * FROM table1, table2 WHERE table1.id = table2.id
UNION ALL
SELECT *, Null, Null FROM table1 WHERE Not table1.id In (SELECT id FROM table2)
UNION ALL
SELECT Null, Null, * FROM table2 WHERE Not table2.id In (SELECT id FROM table1)
--[OR] (recommended for SQLite)
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
UNION ALL
SELECT * FROM table2 LEFT JOIN table1 ON table2.id = table1.id
WHERE table1.id IS NULL
--[OR]
SELECT * FROM table1 FULL OUTER JOIN table2 On table1.id = table2.id
--[Results:]
id | name | id | name
-----+------+------+------
1 | a1 | 1 | a2
2 | b1 | Null | Null
Null | Null | 3 | b2
那么,根据您的需要,您可以选择满足您需求的每一个;).
内部联接.
连接是组合两个表中的行.一个内连接尝试根据您在查询中指定的标准,这两个表匹配,并且只返回匹配的行.如果连接中第一个表中的一行与第二个表中的两个行匹配,则结果中将返回两行.如果第一个表中的某行与第二个表中的行不匹配,则不会返回该行; 同样,如果第二个表中的某行与第一个表中的行不匹配,则不会返回该行.
外加入.
一个左连接试图找到第二个表匹配第一个表中的行的行.如果找不到匹配项,它将返回第一个表中的列,并将第二个表中的列留空(null).
在其他答案中,我没有看到关于性能和优化器的更多细节.
有时候很高兴知道只有INNER JOIN
关联才意味着优化器有最多的选择.它可以重新排序连接顺序,以便更快地保持相同的结果.优化器可以使用最多的连接模式.
通常,尝试使用INNER JOIN
而不是使用不同类型的连接是一种好习惯.(当然,如果可以考虑预期的结果集.)
关于这种奇怪的联想行为,这里有几个很好的例子和解释:
- 左外连接是否相关联?
- 连接顺序在SQL中是否重要?
- 使用一种类型的连接而不是另一种类型的连接可能不是"好的做法".您使用哪种连接决定了您想要的数据.如果你使用另一个,那就错了.另外,在Oracle中至少这个答案是完全错误的.这听起来完全错误,你没有证据.你有证据吗?
-
INNER JOIN
两个或多个表的最典型连接.它返回表ON主键和forignkey关系的数据匹配. -
OUTER JOIN
INNER JOIN
与之相同,但它也包含NULL
ResultSet上的数据.-
LEFT JOIN
=INNER JOIN
+左表的不匹配数据,右表上有Null匹配. -
Null
=RIGHT JOIN
+右表的不匹配数据,左表上有Null匹配. -
INNER JOIN
=Null
+左表和左表上的匹配数据不匹配.
-
- 自联接不是SQL中的关键字,当表引用数据本身知道为自联接时.使用
FULL JOIN
和INNER 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
,LEFT/RIGHT OUTER JOIN
如下:
- 从第一个表中获取每一行:
a
- 考虑旁边第二个表中的所有行:
(a, b[i])
-
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
(就像样品一样)
注意:左连接=左外连接,右连接=右外连接.
在批评了备受喜爱的红色阴影维恩图之后,我认为发布自己的尝试是公平的.
虽然@Martin Smith的答案在很长一段时间内是最好的,但他只显示了每个表中的键列,而我认为理想情况下也应该显示非键列.
在允许的半小时内我能做的最好的事情,我仍然认为它没有充分显示由于缺少键值TableB
或者OUTER JOIN
实际上是联合而不是连接而存在空值:
- 问题是要求INNER和OUTER连接之间的区别,但不一定是左外连接lol
最简单的定义
内部联接:返回两个表中的匹配记录.
完全外部联接:从两个表中返回匹配和不匹配的记录,其中包含来自两个表的不匹配记录的空值.
左外连接:仅从左侧的表中返回匹配和不匹配的记录.
右外连接:仅从右侧的表中返回匹配和不匹配的记录.
简而言之
匹配+左无匹配+右无匹配= 完全外连接
匹配+左无匹配= 左外连接
匹配+右无匹配= 右外连接
匹配= 内部加入
总体思路
请参阅Martin Smith的回答,以获得对不同连接的更好说明和解释,包括特别是,和之间的差异。FULL OUTER JOIN
RIGHT OUTER JOIN
LEFT OUTER JOIN
这两个表构成了JOIN
以下 s表示的基础:
交叉连接
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
得到的结果的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
不合适。
行是不同的。的UNION
是在总7行。但是它们对于一个共同的SQL
结果集是不兼容的。这根本不是 a 的CROSS JOIN
工作方式:
试图这样表示:
..但现在它看起来像一个INTERSECTION
,它肯定不是。此外INTERSECTION
,实际上在两个不同集合中的任何一个中都没有元素。但是,它看起来非常像类似这样的可搜索结果:
作为参考,CROSS JOIN
可以在Tutorialgateway 中看到 s 的一个可搜索结果。的INTERSECTION
,就像这一次,是空的。
内部联接
元素的值取决于JOIN
条件。在每一行对于该条件都变得唯一的条件下表示这一点是可能的。意思id=x
是只有真正的一个排。一旦在表中的一行A
(citizen
)在表中的多个行匹配B
(postalcode
下)JOIN
条件,结果有相同的问题CROSS JOIN
:该行需要被代表多次和集合论是不是真的该做。在唯一性的条件下,图表可以工作,但请记住,JOIN
条件决定了图表中元素的位置。仅查看JOIN
条件值,其余行仅用于骑行:
当使用INNER JOIN
带有ON 1 = 1
条件的a时,这种表示完全崩溃CROSS JOIN
。
用自JOIN
,行是在两个表中实际上idential元素,但表示该表作为既A
与B
不是很适合。例如JOIN
,使元素 inA
与B 中的不同元素匹配的常见自条件是ON A.parent = B.child
,使匹配从A
到B
单独的元素。从SQL
像这样的例子来看:
SELECT *
FROM citizen c1
JOIN citizen c2 ON c1.id = c2.leader
意思是史密斯是格林和詹森的领袖。
外连接
当一行与另一个表中的行有多个匹配时,麻烦又开始了。这更加复杂,因为OUTER JOIN
可以认为匹配空集。但是在集合论中,任何集合C
和空集合的并集总是公正的C
。空集不添加任何内容。这的表示LEFT OUTER JOIN
通常只是显示所有的,A
以说明A
无论是否存在匹配,都会选择in的行B
。然而,“匹配元素”具有与上图相同的问题。它们取决于条件。空集似乎已经徘徊到A
:
WHERE 子句 - 有意义
CROSS JOIN
在月球上用史密斯和邮政编码查找 a 中的所有行:
SELECT *
FROM citizen c
CROSS JOIN postalcode p
WHERE c.name = 'Smith'
AND p.area = 'Moon';
现在维恩图不用于反映JOIN
. 它仅用于WHERE
子句:
..这是有道理的。
当 INTERSECT 和 UNION 有意义时
相交
正如所解释的, anINNER JOIN
并不是真正的INTERSECT
. 但是INTERSECT
s 可用于单独查询的结果。这里维恩图是有道理的,因为来自单独查询的元素实际上是仅属于一个结果或两者的行。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';
联盟
AnOUTER JOIN
不是UNION
。然而,UNION
在与 相同的条件下工作INTERSECT
,导致返回结合两个SELECT
s的所有结果:
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
。
关于这个主题有很多错误信息,包括 Stack Overflow 上的这里。
left join on
(又名left outer join on
)返回inner join on
行union all
通过扩展无与伦比的左表列null
秒。
right join (on
又名 right outer join on
)返回inner join on
行union all
无法比拟的右表行延长了null
秒。
full join on
(又名full outer join on
)返回inner join on
行union all
通过扩展无与伦比的左表中的行null
小号union all
无与伦比的右表中的行通过延长null
秒。
(SQL Standard 2006 SQL/Foundation 7.7 Syntax Rules 1, General Rules 1 b, 3 c & d, 5 b.)
因此,outer join
在您知道所inner join
涉及的基础知识之前,请不要这样做。
找出哪些行inner join on
返回:
SQL 中的 CROSS JOIN 与 INNER JOIN
这也解释了为什么维恩(类)图对内连接和外连接没有帮助。
有关为什么维恩(类似)图对连接没有帮助的更多信息:自然连接的
维恩图
简单来说,
1. INNER JOIN或EQUI JOIN:返回仅匹配两个表中的条件的结果集.
2. OUTER JOIN:即使条件匹配与否,也返回两个表中所有值的结果集.
3. LEFT JOIN:返回左表中所有值的结果集,只返回与右表中的条件匹配的行.
4. RIGHT JOIN:返回右表中所有值的结果集,只返回与左表中的条件匹配的行.
5. 完全加入:完全加入和全外加入是相同的.
1.内连接:也称为连接。它仅在存在 match 时返回 Left table 和 right table 中存在的行。否则,它返回零记录。
例子:
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.右外连接:也称为右连接。它从左表(如果有)返回匹配的行,以及右表中存在的所有行。
联接的优势
- 执行速度更快。
- 只有当表具有相同的列集时,这才是正确的。(它混淆了内部连接与交集和完全连接与联合。)“匹配”也是未定义的。阅读我的其他评论。