怎么办呢 LEFT JOIN
, RIGHT JOIN
和 FULL JOIN
适合?
怎么办呢 LEFT JOIN
, RIGHT JOIN
和 FULL JOIN
适合?
假设您正在加入没有重复的列,这是一种非常常见的情况:
A和B的内连接给出A交叉B的结果,即a的内部 维恩图 路口。
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
维恩图并没有真正为我做这件事。
例如,它们没有显示交叉连接和内连接之间的任何区别,或者更一般地显示不同类型的连接谓词之间的任何区别,或者提供用于推理它们将如何操作的框架。
理解逻辑处理是无可替代的,无论如何都要相对简单。
on
对来自步骤1的所有行保留谓词计算结果的子句 true
(注意:在实践中,查询优化器可能会找到比上面的纯逻辑描述更有效的执行查询的方法,但最终结果必须相同)
我将从一个动画版开始 全外连接。进一步说明如下。
来源表
首先从a开始 CROSS JOIN
(AKA笛卡尔积)。这没有 ON
子句并简单地返回两个表中的每个行组合。
SELECT A.Colour,B.Colour from A CROSS JOIN B
内部和外部联接具有“ON”子句谓词。
SELECT A.Colour,B.Colour from A INNER JOIN B ON A.Colour = B.Colour
以上是经典的equi join。
内连接条件不一定是相等条件,也不需要引用来自两个(或甚至任何一个)表的列。评估 A.Colour NOT IN ('Green','Blue')
在交叉连接的每一行返回。
选择A.Colour,B.Colour from INNER JOIN B ON 1 = 1
对于交叉连接结果中的所有行,连接条件的计算结果为true,因此这与交叉连接相同。我不会再重复16行的图片了。
外连接的逻辑评估方式与内连接的方式相同,只是如果左表中的一行(左连接)不与右表中的任何行连接,它将保留在结果中 NULL
右栏的值。
这只是将前一个结果限制为只返回行所在的位置 B.Colour IS NULL
。在这种特殊情况下,这些将是保留的行,因为它们在右侧表中没有匹配,并且查询返回表中不匹配的单个红色行 B
。这被称为反半连接。
选择一列是很重要的 IS NULL
测试不是可空的,或者连接条件确保任何 NULL
将排除这些值以使此模式正常工作,并避免只返回碰巧有的行 NULL
除了未匹配的行之外,该列的值。
右外连接的作用类似于左外连接,除了它们保留右表中的非匹配行,并且null扩展左侧列。
完全外连接组合了左连接和右连接的行为,并保留左表和右表的不匹配行。
交叉连接中的任何行都不匹配 1=0
谓词。使用常规外部联接规则保留两侧的所有行,并在另一侧的表中使用NULL。
通过对前面的查询的一个小修改,可以模拟a UNION ALL
这两张桌子。
请注意 WHERE
子句(如果存在)在连接后逻辑运行。一个常见错误是执行左外连接,然后在右表上包含一个WHERE子句,该子句最终排除不匹配的行。以上结果执行外连接...
...然后“Where”子句运行。 NULL= 'Green'
不评估为true,因此外部联接保留的行最终被丢弃(与蓝色一起),有效地将联接转换回内部联接。
如果意图仅包括B中的行,其中Color为绿色,而所有来自A的行都不包括正确的语法
见这些例子 在SQLFiddle.com上运行。
以下摘自文章“MySQL - LEFT JOIN和RIGHT JOIN,INNER JOIN和OUTER JOIN“格雷厄姆埃利斯在他的博客马口上。
在像MySQL这样的数据库中,数据被分成许多表,然后连接(Joined
)一起来 JOIN
在 SELECT
用于从多个表中读取记录的命令。阅读此示例以了解其工作原理。
首先,一些样本数据:
people
mysql> select * from people;
+------------+--------------+------+
| name | phone | pid |
+------------+--------------+------+
| Mr Brown | 01225 708225 | 1 |
| Miss Smith | 01225 899360 | 2 |
| Mr Pullen | 01380 724040 | 3 |
+------------+--------------+------+
3 rows in set (0.00 sec)
property
mysql> select * from property;
+------+------+----------------------+
| pid | spid | selling |
+------+------+----------------------+
| 1 | 1 | Old House Farm |
| 3 | 2 | The Willows |
| 3 | 3 | Tall Trees |
| 3 | 4 | The Melksham Florist |
| 4 | 5 | Dun Roamin |
+------+------+----------------------+
5 rows in set (0.00 sec)
定期加入
如果我们进行常规JOIN(没有关键字INNER,OUTER,LEFT或RIGHT),那么我们将获得在两个表中以适当方式匹配的所有记录,并且不报告两个不匹配的传入表中的记录:
mysql> select name, phone, selling
from people join property
on people.pid = property.pid;
+-----------+--------------+----------------------+
| name | phone | selling |
+-----------+--------------+----------------------+
| Mr Brown | 01225 708225 | Old House Farm |
| Mr Pullen | 01380 724040 | The Willows |
| Mr Pullen | 01380 724040 | Tall Trees |
| Mr Pullen | 01380 724040 | The Melksham Florist |
+-----------+--------------+----------------------+
4 rows in set (0.01 sec)
LEFT JOIN
如果我们进行LEFT JOIN,我们会以相同的方式获得匹配的所有记录,并且在IN ADDITION中我们为连接的左表中的每个不匹配的记录获得额外的记录 - 从而确保(在此示例中)每个PERSON都被提及:
mysql> select name, phone, selling
from people left join property
on people.pid = property.pid;
+------------+--------------+----------------------+
| name | phone | selling |
+------------+--------------+----------------------+
| Mr Brown | 01225 708225 | Old House Farm |
| Miss Smith | 01225 899360 | NULL <<-- unmatch |
| Mr Pullen | 01380 724040 | The Willows |
| Mr Pullen | 01380 724040 | Tall Trees |
| Mr Pullen | 01380 724040 | The Melksham Florist |
+------------+--------------+----------------------+
5 rows in set (0.00 sec)
正确的加入
如果我们进行RIGHT JOIN,我们会获得匹配的所有记录和IN ADDITION为连接右表中每个不匹配记录的额外记录 - 在我的示例中,这意味着即使我们不这样做,每个属性也会被提及有卖家详情:
mysql> select name, phone, selling
from people right join property
on people.pid = property.pid;
+-----------+--------------+----------------------+
| name | phone | selling |
+-----------+--------------+----------------------+
| Mr Brown | 01225 708225 | Old House Farm |
| Mr Pullen | 01380 724040 | The Willows |
| Mr Pullen | 01380 724040 | Tall Trees |
| Mr Pullen | 01380 724040 | The Melksham Florist |
| NULL | NULL | Dun Roamin |
+-----------+--------------+----------------------+
5 rows in set (0.00 sec)
INNER JOIN执行完全连接,就像第一个示例一样,在最后两个示例中,可以在LEFT或RIGHT之后添加单词OUTER - 它提供了ODBC兼容性,并且不添加额外的功能。
仅检索匹配的行,即 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值来满足连接谓词时,每个匹配的行对的列值 雇员 和 位置 被合并到一个结果行中。 以下是内连接的SQL的外观:
select * from employee inner join location on employee.empID = location.empID
OR
select * from employee, location where employee.empID = location.empID
现在,这是运行SQL的结果如下:
外部加入: - 外连接不要求两个连接表中的每个记录都具有匹配的记录。即使没有其他匹配记录,联接表也会保留每条记录。外连接进一步细分为左外连接和右外连接,具体取决于保留哪个表的行(左或右)。
左外连接: - 表的左外连接(或简称左连接)的结果 雇员 和 位置 始终包含“左”表的所有记录(雇员),即使连接条件在“右”表中找不到任何匹配的记录(位置)。 以下是使用上表的左外连接的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
使用上面的表格,我们可以显示右外连接的结果集是什么样的:
完整的外部联接: -
完全外连接或完全连接是通过在连接的结果中包含不匹配的行来保留不匹配的信息,使用完全外连接。它包括来自两个表的所有行,无论另一个表是否具有匹配值。
简单来说:
一个 内部联接 仅检索匹配的行。
而a 外连接 从一个表和其他表中的所有行检索匹配的行....结果取决于您使用的是哪一行:
剩下:右表中匹配的行和左表中的所有行
对:左表中匹配的行和右表中的所有行或
充分:所有表中的所有行。是否有匹配并不重要
如果在连接的另一侧(右侧)存在匹配记录,则内部联接仅显示行。
(左)外连接显示左侧每条记录的行,即使连接的另一侧(右侧)没有匹配的行。如果没有匹配的行,则另一侧(右侧)的列将显示NULL。