SQL-连接(JOIN)专题
SQL 最强大的功能之一就是能在数据检索查询的执行中联结(join)表。联结是利用 SQL 的 SELECT 能执行的最重要的操作,很好地理解联结及其语法是学习 SQL 的一个极为重要的组成部分。另外聚集函数也可以在联结中进行使用。
SQL 连接(JOIN) 用于把来自两个或多个表的行结合起来。
下图展示了 LEFT JOIN、RIGHT JOIN、INNER JOIN、OUTER JOIN 相关的 7 种用法。
在我们继续讲解实例之前,我们先列出您可以使用的不同的 SQL JOIN 类型:
INNER JOIN:如果表中有至少一个匹配,则返回行
LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行
RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行
FULL JOIN:只要其中一个表中存在匹配,则返回行
前提准备
导入语句
1 | CREATE TABLE IF NOT EXISTS `access_log` ( |
预览数据
1 | MariaDB [test]> SELECT * FROM websites; |
叉联结
笛卡儿积(cartesian product) 由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。
有时我们会听到返回称为叉联结(cross join)的笛卡儿积的联结类型。
SQL INNER JOIN 内联结(交集)
INNER JOIN 关键字在表中存在匹配时返回行。
语法
1 | SELECT column_name(s) |
可省略 INNER 关键字:
1 | SELECT column_name(s) |
注释:INNER JOIN 与 JOIN 是相同的。
示例:返回所有网站的访问记录
1 | MariaDB [test]> SELECT Websites.name, access_log.count, access_log.date |
外联结
SQL LEFT JOIN 语法
LEFT JOIN 关键字从左表(table1)返回所有的行,即使右表(table2)中没有匹配。如果右表中没有匹配,则结果为 NULL。
SQL LEFT JOIN 语法
1 | SELECT column_name(s) |
或:
1 | SELECT column_name(s) |
下面的 SQL 语句将返回所有网站及他们的访问量(如果有的话)。
1 | MariaDB [test]> SELECT Websites.name, access_log.count, access_log.date |
注释:LEFT JOIN 关键字从左表(Websites)返回所有的行,即使右表(access_log)中没有匹配。
SQL RIGHT JOIN 语法
RIGHT JOIN 关键字从右表(table2)返回所有的行,即使左表(table1)中没有匹配。如果左表中没有匹配,则结果为 NULL。
1 | SELECT column_name(s) |
或:
1 | SELECT column_name(s) |
注释:在某些数据库中,RIGHT JOIN 称为 RIGHT OUTER JOIN。
1 | MariaDB [test]> SELECT Websites.name, access_log.count, access_log.date |
由此我们还能得出结论,表 A 左外连接表 B 等价于 表 B 右外连接表 A。
事实上左外联结和右外联结。它们之间的唯一差别是所关联的表的顺序。换句话说,调整FROM或WHERE子句中表的顺序,左外联结可以转换为右外联结。因此,这两种外联结可以互换使用,哪个方便就用哪个。
SQL FULL OUTER JOIN 全外连接
FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配,则返回行.
FULL OUTER JOIN 关键字结合了 LEFT JOIN 和 RIGHT JOIN 的结果。
注意:MariaDB、MySQL 和 SQLite 不支持 FULL OUTER JOIN 语法。你可以在 SQL Server 测试以下实例。
SQL FULL OUTER JOIN 语法
1 | SELECT column_name(s) |
mysql 的写法
1 | mysql> select * from t1 left join t2 on t1.id = t2.id |
并集去交集
1 | mysql> select * from t1 left join t2 on t1.id = t2.id where t2.id is null |
多个连接的写法总结
INNER JOIN 连接两个数据表的用法:
1 | SELECT * FROM 表1 |
INNER JOIN 连接三个数据表的用法:
1 | SELECT * FROM 表1 |
自联结
自联结通常作为外部语句,用来替代从相同表中检索数据的使用子查询语句。虽然最终的结果是相同的,但许多 DBMS 处理联结远比处理子查询快得多。应该试一下两种方法,以确定哪一种的性能更好。
自然联结
标准的联结(前一课中介绍的内联结)返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使每一列只返回一次。
自然联结要求你只能选择那些唯一的列,一般通过对一个表使用通配符(SELECT*),而对其他表的列使用明确的子集来完成。
事实上,我们迄今为止建立的每个内联结都是自然联结,很可能永远都不会用到不是自然联结的内联结。
联结的性能考虑
注意:性能考虑 DBMS 在运行时关联指定的每个表,以处理联结。这种处理可能非常耗费资源,因此应该注意:
- 不要联结不必要的表。联结的表越多,性能下降越厉害。
- 应该总是提供联结条件,否则会得出笛卡儿积。
1 | SELECT cust_name, cust_contact |
子查询并不总是执行复杂 SELECT 操作的最有效方法,以下语句也可使用联结的相同查询。
多做实验 正如所见,为执行任一给定的SQL操作,一般存在不止一种方法。很少有绝对正确或绝对错误的方法。性能可能会受操作类型、表中数据量、是否存在索引或键以及其他一些条件的影响。因此,有必要对不同的选择机制进行实验,以找出最适合具体情况的方法。
1 | SELECT cust_name, cust_contact FROM customers |
例题
提问:查找值等于或大于 1000 的所有订单号和订单数量至少达到这个数的顾客名称。
解答:可以使用使用简单的等联结或 ANSI 的 INNER JOIN 语法。
1 | -- Equijoin syntax |
参考
SQL UNION 操作符 | 菜鸟教程
https://www.runoob.com/sql/sql-union.html
SQL必知必会(第5版)-本·福达-微信读书https://weread.qq.com/web/reader/f7632a30720befadf7636bb