What is the difference between “INNER JOIN” and “OUTER JOIN”?
又是怎样做的呢?
假设您连接的列没有重复项,这是非常常见的情况:
A和B的内部连接给出了相交B的结果,即维恩图相交的内部部分。
A和B的外部连接给出了联合B的结果,即维恩图联合的外部部分。
实例
假设您有两个表,每个表只有一列,数据如下:
1 2 3 4 5 6 | A B - - 1 3 2 4 3 5 4 6 |
请注意,(1,2)对于A是唯一的,(3,4)对于B是唯一的,(5,6)对于B是唯一的。
内连接
使用任意一个等价查询的内部联接提供两个表的交集,即它们有共同的两行。
1 2 3 4 5 6 7 | 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中的任何公共行。
1 2 3 4 5 6 7 8 9 | 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中的任何公共行。
1 2 3 4 5 6 7 8 9 | 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部分为空,反之亦然。
1 2 3 4 5 6 7 8 9 10 | 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 |
此外,您还可以为不同的连接类型考虑以下模式;
来源:C.L.Moffatt详细解释的SQL连接的可视化表示
我推荐杰夫的博客文章。我所见过的最好的描述,加上有一个可视化,例如:
内部连接:
完全外部联接:
维恩图并不是真的适合我。好的。
例如,它们不显示交叉联接和内部联接之间的任何区别,或者更一般地显示不同类型的联接谓词之间的任何区别,或者提供一个关于它们将如何操作的推理框架。好的。
理解逻辑处理是不可替代的,不管怎样,它都比较容易掌握。好的。
(注意:在实践中,查询优化程序可能会找到比上述纯逻辑描述更有效的执行查询的方法,但最终结果必须相同)好的。
我将从一个完整的外部连接的动画版本开始。下面是进一步的解释。好的。
好的。解释
源表好的。
好的。
首先从
从交叉连接中选择A.颜色,B.颜色好的。
好的。
内部和外部联接有一个"on"子句谓词。好的。
- 内部连接。为交叉联接结果中的所有行计算"on"子句中的条件。如果为真,则返回联接的行。否则丢弃它。
- 左外联接。对于左表中不匹配任何内容的任何行,与inner join相同。使用右表列的空值输出这些内容。
- 右外部连接。对于右表中不匹配任何内容的任何行,与内部联接相同。将这些行与左表列的空值输出。
- 完全外部联接。与内部联接相同,然后按照左外部联接保留左不匹配行,按照右外部联接保留右不匹配行。
一些实例
从内部连接中选择A.颜色,B.颜色A.颜色=B.颜色好的。
上面是典型的equi连接。好的。
好的。动画版本
好的。从内部连接中选择A.颜色,B.颜色A.颜色不在(‘绿色’、‘蓝色’)
内部联接条件不必是相等条件,也不需要引用来自两个表(甚至其中一个表)的列。在交叉联接返回的每一行上计算
好的。
从1=1的内部连接B中选择A.颜色,B.颜色好的。
对于交叉联接结果中的所有行,联接条件的计算结果都为true,因此这与交叉联接相同。我不会再重复16行的图片了。好的。从左侧外部连接处选择A.颜色,B.颜色A.颜色=B.颜色
外部联接的逻辑计算方式与内部联接相同,但如果左表中的一行(对于左联接)根本不与右表中的任何行联接,则在结果中保留右表中的
好的。从左侧外部连接处选择A.颜色,B.颜色,A.颜色=B.颜色,其中B.颜色为空
这只会限制前面的结果只返回
为
好的。从右侧外部连接处选择A.颜色,B.颜色A.颜色=B.颜色
右外部联接的作用类似于左外部联接,但它们保留右表中不匹配的行,空扩展左列。好的。
好的。从一个完整的外部连接中选择A.颜色,B.颜色,A.颜色=B.颜色
完全外部联接结合了左联接和右联接的行为,并保留左表和右表中不匹配的行。好的。
好的。从1=0的完整外部连接B中选择A.颜色,B.颜色
交叉联接中没有与
好的。从1=0的完整外部连接B中选择"合并"(a.colour,b.colour)作为颜色。
通过对前面的查询进行较小的修改,可以模拟两个表中的
好的。从左侧外部连接B中选择A.颜色,B.颜色A.颜色=B.颜色,其中B.颜色=绿色
注意,
好的。
…然后是"where"子句。
好的。
如果只包含b中颜色为绿色的行和a中的所有行,不管正确的语法是什么好的。在A.colour=B.colour和B.colour='green'上从左侧外部连接B中选择A.colour、B.colour
好的。SQL小提琴
请参阅sqlfiddle.com上运行的这些示例。好的。好啊。
联接用于组合来自两个表的数据,其结果是一个新的临时表。连接是基于一个叫做谓词的东西来执行的,它指定了执行连接时要使用的条件。内部联接和外部联接的区别在于,内部联接只返回基于联接谓词实际匹配的行。让我们考虑雇员和位置表:
内部连接:内部联接通过基于联接谓词组合两个表(雇员和位置)的列值来创建新的结果表。查询将雇员的每一行与位置的每一行进行比较,以查找满足联接谓词的所有行对。当通过匹配非空值来满足联接谓词时,Employee和Location的每对匹配行的列值都被合并到结果行中。内部联接的SQL如下所示:
1 2 3 | 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)的所有记录,即使联接条件在"右"表(location)中找不到任何匹配的记录。下面是左外部联接的SQL,使用上面的表:
1 2 | SELECT * FROM employee LEFT OUTER JOIN location ON employee.empID = location.empID; //USE OF OUTER keyword IS optional |
现在,运行此SQL的结果如下:
右外部连接:右外部联接(或右联接)与左外部联接非常相似,除非对表进行相反的处理。"右"表(位置)中的每一行将至少出现在联接表中一次。如果"左"表(Employee)中不存在匹配行,则对于位置不匹配的记录,Employee中的列将显示空值。这就是SQL的样子:
1 2 | SELECT * FROM employee RIGHT OUTER JOIN location ON employee.empID = location.empID; //USE OF OUTER keyword IS optional |
使用上面的表,我们可以显示右外部联接的结果集是什么样子的:
号
全外部连接:完全外部联接或完全联接是通过在联接的结果中包含不匹配的行来保留不匹配的信息,请使用完全外部联接。它包括两个表中的所有行,不管另一个表是否具有匹配的值。
图像源
mysql 8.0参考手册-连接语法
Oracle加入操作
内连接
只检索匹配的行,即
1 2 3 4 | SELECT * FROM dbo.Students S INNER JOIN dbo.Advisors A ON S.Advisor_ID = A.Advisor_ID |
左外连接
从第一个表中选择所有记录,在第二个表中选择任何记录与联接键匹配的表。
1 2 3 4 | SELECT * FROM dbo.Students S LEFT JOIN dbo.Advisors A ON S.Advisor_ID = A.Advisor_ID |
全外部连接
从第二个表中选择所有记录,并选择第一个表中的所有记录与联接键匹配的表。
1 2 3 4 | SELECT * FROM dbo.Students S FULL JOIN dbo.Advisors A ON S.Advisor_ID = A.Advisor_ID |
工具书类
内部和外部联接SQL示例和联接块
SQL:连接
简单来说:
内部联接只检索匹配的行。
而外部联接从一个表中检索匹配的行,并从另一个表中检索所有行……结果取决于您使用的行:
左:右表中的匹配行和左表中的所有行
右:左表中的匹配行和右表中的所有行或
完整:所有表中的所有行。有没有火柴没关系
只有在联接的另一侧(右侧)有匹配记录时,内部联接才会显示行。
(左)外部联接在左侧显示每条记录的行,即使联接的另一侧(右)上没有匹配的行。如果没有匹配的行,则另一侧(右侧)的列将显示空值。
内部联接要求联接表中存在具有相关ID的记录。
外部联接将返回左侧的记录,即使右侧不存在任何记录。
例如,您有一个orders和一个orderdetails表。它们通过"orderID"关联。
命令
- 订单编号
- 客户名称
订单详情
- 有序细节
- 订单编号
- 产品名称
- 数量
- 价格
请求
1 2 3 4 | SELECT Orders.OrderID, Orders.CustomerName FROM Orders INNER JOIN OrderDetails ON Orders.OrderID = OrderDetails.OrderID |
将只返回在orderdetails表中也有内容的订单。
如果您将其更改为左外联接
1 2 3 4 | SELECT Orders.OrderID, Orders.CustomerName FROM Orders LEFT JOIN OrderDetails ON Orders.OrderID = OrderDetails.OrderID |
然后它将从orders表返回记录,即使它们没有orderdetails记录。
通过添加一个像
简单来说:
inner join->仅从父表和子表中获取公用记录,其中父表的主键与子表中的外键匹配。
左连接>
伪码
1 2 3 4 5 6 7 8 | 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. } } |
右连接:与左连接完全相反。在右联接中,将左联接中的表名放在右联接中的右侧,得到与左联接相同的输出。
外部联接:显示两个表中的所有记录
例子:
现在假设两张桌子
1 2 3 | employees : id , name phone_numbers_employees : id , phone_num , emp_id |
这里,employees表是主表,phone_numbers_employees是子表(它包含作为连接
内连接
只有当Employees表的主键(其ID)与子表Phone_Numbers_Employees(EMP_ID)的外键匹配时,才取2个表的记录。
所以查询应该是:
1 | 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; |
这里只取主键=外键上的匹配行,如上所述。这里,主键=外键上的不匹配行由于联接而被跳过。
左连接:
左联接保留左表的所有行,而不管右表上是否有匹配的行。
1 | 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; |
外部连接:
1 | 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; |
从图中可以看出:
使用
在
对于所有类型的连接,这是一个很好的图表解释。
来源:http://ssiddique.info/understanding-sql-joins-in-easy-way.html
同样,
答案是每一个的意义,所以在结果中。
Note :
InSQLite there is noRIGHT OUTER JOIN orFULL OUTER JOIN .
And also inMySQL there is noFULL OUTER JOIN .
我的答案是基于上面的笔记。
如果有两张这样的桌子:
1 2 3 4 5 | --[table1] --[table2] id | name id | name ---+------- ---+------- 1 | a1 1 | a2 2 | b1 3 | b2 |
交叉连接/外部连接:您可以使用
1 2 3 4 5 6 7 8 9 10 11 | 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 |
内部连接:当您想根据像
1 2 3 4 5 6 7 8 | 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 |
左[外部]连接:当您希望在上面的结果中有一个表的所有行(具有相同的关系)时,可以使用
1 2 3 4 5 6 7 8 9 10 11 | 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 |
完全外部联接:当您还希望在结果中包含其他表的所有行时,可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 |
嗯,根据您的需要,您可以选择满足您需要的每一个;)。
内部连接。
联接正在合并两个表中的行。内部联接将根据您在查询中指定的条件来匹配这两个表,并且只返回匹配的行。如果联接中第一个表中的一行与第二个表中的两行匹配,则结果中将返回两行。如果第一个表中有一行与第二个表中的一行不匹配,则不会返回该行;同样,如果第二个表中有一行与第一个表中的一行不匹配,则不会返回该行。
外部连接。
左联接尝试查找从第一个表到第二个表中的行的匹配。如果找不到匹配项,它将返回第一个表中的列,并将第二个表中的列留空(空)。
在其他答案中,我看不到关于性能和优化器的详细信息。
有时很好地知道只有
一般来说,尝试使用
关于这种奇怪的联想行为,这里有几个很好的例子和解释:
- 左外部联接是否关联?
- SQL中的联接顺序有关系吗?
- 当条件评估为
true 时,返回合并行(a, b[i]) 。 - 当到达第二个表的末尾而没有任何匹配时,这是一个
OUTER JOIN ,然后使用Null 为其他表的所有列返回一个(虚拟)对:(a, Null) 表示左外部联接,(Null, b) 表示右外部联接。这是为了确保第一个表的所有行都存在于最终结果中。
注意:
... ON T1.title = T2.title AND T1.version < T2.version (=>请参阅本文作为示例用法:仅选择列上最大值的行)... ON T1.y IS NULL ... ON 1 = 0 (同样品)
注:左联接=左外联接,右联接=右外联接。
在批评了广受欢迎的红色阴影维恩图之后,我认为发表我自己的尝试是公平的。
虽然@martin smith的答案在很长一段时间内是最好的,但他只显示每个表中的键列,而我认为理想情况下也应该显示非键列。
在允许的半小时内,我能做的最好的一点是,我仍然认为它不能充分地显示空值是由于
最简单的定义
内部联接:返回两个表中匹配的记录。
完全外部联接:返回两个表中匹配的和不匹配的记录,对于两个表中不匹配的记录,返回空值。
左外部联接:仅从左侧的表返回匹配和不匹配的记录。
右外部联接:仅从右侧的表返回匹配和不匹配的记录。
简而言之
匹配+左不匹配+右不匹配=完全外部联接
匹配+左不匹配=左外部联接
匹配+右不匹配=右外部联接
匹配=内部联接
inner join 两个或多个表的最典型联接。它返回primarykey和forignkey关系表上的数据匹配。outer join 与inner join 相同,但也包括NULL 结果集的数据。LEFT JOIN =inner join +左表数据不匹配,右表NULL 匹配。RIGHT JOIN =inner join +左表NULL 匹配右表不匹配数据。FULL JOIN =inner join +与NULL 匹配的左、右表数据不匹配。
- 在SQL中,当表引用自身的数据时,self-join不是关键字。使用
inner join 和outer join 我们可以编写自连接查询。
例如:
1 2 3 4 5 6 | 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 |
What is the difference between"INNER JOIN" and"OUTER JOIN"?
它们是SQL中最常用的存在主义运算符,其中
考虑这些查询:
1 2 | users who have posted AND have votes users who have posted but have no badges |
寻找基于集合的解决方案(行业术语)的人会将各自的查询识别为:
1 2 | users who have posted INTERSECT users who have votes users who have posted MINUS users who have badges |
将这些转换为标准SQL:
1 2 3 4 5 6 7 | SELECT UserId FROM Posts INTERSECT SELECT UserId FROM Votes; SELECT UserId FROM Posts EXCEPT SELECT UserId FROM Badges; |
其他人则会按照类似的集合包含方式思考:
1 2 | users who have posted AND IN the SET OF users who have votes users who have posted AND NOT IN the SET OF users who have badges |
将这些转换为标准SQL:
1 2 3 4 5 6 7 | SELECT UserId FROM Posts WHERE UserId IN ( SELECT UserId FROM Votes ); SELECT UserId FROM Posts WHERE UserId NOT IN ( SELECT UserId FROM Badges ); |
有些人会考虑在集合内的"存在",例如
1 2 | users who have posted AND EXIST IN the SET OF users who have votes users who have posted AND do NOT EXIST IN the SET OF users who have badges |
将这些转换为标准SQL(注意,我们现在需要使用范围变量,即
1 2 3 4 5 6 7 8 9 10 11 | SELECT p.UserId FROM Posts p WHERE EXISTS ( SELECT * FROM Votes v WHERE v.UserId = p.UserId ); SELECT p.UserId FROM Posts p WHERE NOT EXISTS ( SELECT * FROM Badges b WHERE b.UserId = p.UserId ); |
但是,我发现"行业标准"方法是专门使用连接。我不知道这里的想法是什么(仪器定律?过早优化?),所以我将直接转到语法:
1 2 3 4 5 6 7 8 | SELECT p.UserId FROM Posts p INNER JOIN Votes v ON v.UserId = p.UserId; SELECT p.UserId FROM Posts p LEFT JOIN Badges b ON b.UserId = p.UserId WHERE b.UserId IS NULL; |
需要注意的事项:
- 唯一的投影来自
Users ,但是我们仍然需要所有这些范围变量(p 、v 、b 来搜索条件。 UserId IS NULL 搜索条件"属于"OUTER JOIN 但在查询中断开连接。LEFT 是行业标准:专业人员会重写查询,避免使用RIGHT !- 省略
LEFT OUTER JOIN 中的OUTER 关键字。
闭幕词:
有时连接仅用于查询,以确定值是否存在于另一个集合中。学习仔细查看正在投影的属性(
简单来说,
1.inner join或equi join:返回仅与两个表中的条件匹配的结果集。
2.外部联接:返回两个表中所有值的结果集,即使条件是否匹配。
3.左联接:返回左表中所有值的结果集,仅返回与右表中条件匹配的行。
4.右联接:返回右表中所有值的结果集,仅返回与左表中条件匹配的行。
5.完全联接:完全联接和完全外部联接相同。
1.内部联接:也称为联接。它返回左表和右表中的行,只有在匹配时才返回。否则,它返回零个记录。
例子:
1 2 3 4 5 6 | SELECT e1.emp_name, e2.emp_salary FROM emp1 e1 INNER JOIN emp2 e2 ON e1.emp_id = e2.emp_id |
2.完全外部联接:也称为完全联接。它返回左表和右表中的所有行。
例子:
1 2 3 4 5 6 | SELECT e1.emp_name, e2.emp_salary FROM emp1 e1 FULL OUTER JOIN emp2 e2 ON e1.emp_id = e2.emp_id |
3.左外联接:或简称左联接。它返回左表中的所有行以及右表中的匹配行(如果有)。
4.右外接:又称右接。它返回左表中的匹配行(如果有),以及右表中的所有行。
连接的优点
内部联接-使用任一等效查询的内部联接提供两个表的交集,即它们共有的两行。
左外部联接-左外部联接将提供A中的所有行,以及B中的所有公共行。
完全外部联接-完全外部联接将为您提供A和B的联接,即A中的所有行和B中的所有行。如果A中的某个内容在B中没有相应的数据,则B部分为空,副versay
(SQL标准2006 SQL/FAST 7.7语法规则1,一般规则1 B,3 C和D,5 B)
所以在你知道
找出
阅读我的评论有许多困惑和糟糕的答案。
然后阅读我的评论这里有许多困惑和糟糕的答案。
内部连接和外部连接的区别如下:
考虑以下两个表:
电磁脉冲
1 2 3 4 5 6 7 | 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 |
系
1 2 3 4 5 6 | deptid name 1 IT 2 Accounts 3 Security 4 HR 5 R&D |
内部连接:
主要是作为SQL查询中的join编写的。它只返回表之间匹配的记录。
找出所有员工及其部门名称:1 2 3 4 5 6 7 8 9 10 11 12 | 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打印
所以,内部联接或只是联接,只返回匹配的行。
左连接:这将返回左表中的所有记录,并且仅匹配右表中的记录。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
因此,如果您观察上面的输出,那么左表(EMP)中的所有记录都将打印为右表中的匹配记录。
所以,左联接返回左表中的所有行,并且只匹配右表中的行。
也可以在这里查看演示。