本文将从连接的理论和语法讲起,结合具体的例子,详细分析 SQL 连接。

之前对数据库的连接操作似懂非懂,大概知道是什么东西,但是面试笔试的时候被虐成渣,讲不清连接到底是什么。吃一堑,长一智。这就是所谓的似懂非懂, 只是单纯的看书是没用的,只有亲自动手做实验才能彻底理解什么是连接。

连接类型与条件

SQL 中每一种连接操作都包括一个连接类型和连接条件。

连接类型

连接类型决定了如何处理连接条件不匹配的记录。

连接类型 返回结果
inner join 只包含左右表中满足连接条件的记录
left outer join 在内连接的基础上,加入左表中不与右表匹配的记录,剩余字段赋值为null
right outer join 在内连接的基础上,加入右表中不与左表匹配的记录,剩余字段赋值为null
full outer join 左外连接和右外连接的组合。
cross join 等价于没有连接条件的内连接(即产生笛卡尔乘积)

关键字 inner 和 outer 是可选的,因为根据连接类型的其余内容我们可以判断出连接是内连接和外连接。简单来说就是:除了单独的 join 是内连接,其他都是外连接。

对外连接来说,连接条件是 必须的 ;但对内连接来说,连接条件是 可选的 (如果省略,将产生笛卡尔积)。

连接条件

连接条件决定两个表中哪些记录互相匹配以及连接结果中出现哪些属性。

连接条件 修饰位置 语义
natural 连接类型之前 连接两个表之间的所有公共字段相等的记录,合并相同的列
on <谓词> 连接类型之后 连接符合谓词的记录,不合并相同的列
using(A1, A2,…,An) 连接类型之后 natural 语义的子集,只连接两个表中(A1,A2,..An)的公共字段,合并相同的列

从上面的描述可以看到:连接操作是连接类型和连接条件的组合,只有在这个前提下才能真正的理解连接的功能。

FQA

例子中使用到的表

student

+----+--------+
| id | name |
+----+--------+
| | 张三 |
| | 李四 |
| | 王二 |
| | 初一 |
| | 初二 |
+----+--------+
teacher +----+-----------+
| id | name |
+----+-----------+
| | 王老师 |
| | 李老师 |
| | 张老师 |
| | 肖老师 |
| | NULL |
| | 陈老师 |
+----+-----------+
course +----+--------+------+
| id | cname | tid |
+----+--------+------+
| | 数学 | |
| | 英语 | |
| | 语文 | |
| | 体育 | |
| | 物理 | NULL |
+----+--------+------+
student_course +-----+-----+
| sid | cid |
+-----+-----+
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
+-----+-----+

内连接之后的结果集数量是多少?等于左表或者右表中记录的数量吗?

内连接 teacher course 的结果

select * from teacher inner join course on teacher.id = course.tid;
+----+-----------+----+--------+------+
| id | name | id | cname | tid |
+----+-----------+----+--------+------+
| | 王老师 | | 数学 | |
| | 李老师 | | 英语 | |
| | 张老师 | | 语文 | |
| | 王老师 | | 体育 | |
+----+-----------+----+--------+------+

可以发现,王老师同时教数学和体育,因此左表中王老师匹配了右表中两条记录,物理没有老师教,所以没有出现在结果中。说明 内连接的结果集数量等于左右表中匹配记录的数量 。

左连接之后的结果集数量是多少?等于左表的记录数量吗?

左连接 teacher course 的结果

select * from teacher left join course on teacher.id = course.tid;
+----+-----------+------+--------+------+
| id | name | id | cname | tid |
+----+-----------+------+--------+------+
| | 王老师 | | 数学 | |
| | 李老师 | | 英语 | |
| | 张老师 | | 语文 | |
| | 王老师 | | 体育 | |
| | 肖老师 | NULL | NULL | NULL |
| | NULL | NULL | NULL | NULL |
| | 陈老师 | NULL | NULL | NULL |
+----+-----------+------+--------+------+

可以看到,没有教授课程的老师也出现在结果中,对应的字段都为NULL。说明结果集的数量并不等于左表记录的数量,因为两个表直接不是一对一的关系。其数量应该等于 内连接的结果集数量加上左表中不匹配的记录数量 。

Mysql 中不支持 full outer join

可以通过 union 操作模拟。

SELECT * FROM teacher
LEFT JOIN course ON teacher.id = course.tid
UNION
SELECT * FROM teacher
RIGHT JOIN course ON teacher.id = course.id; +------+-----------+------+--------+------+
| id | name | id | cname | tid |
+------+-----------+------+--------+------+
| | 王老师 | | 数学 | |
| | 李老师 | | 英语 | |
| | 张老师 | | 语文 | |
| | 王老师 | | 体育 | |
| | 肖老师 | NULL | NULL | NULL |
| | NULL | NULL | NULL | NULL |
| | 陈老师 | NULL | NULL | NULL |
| | 肖老师 | | 体育 | |
| | NULL | | 物理 | NULL |
+------+-----------+------+--------+------+
多表连接问题 考虑查出所有学生的课程的记录 select * from student
left join student_course on student.id = student_course.sid
left join course on student_course.cid = course.id; +----+--------+------+------+------+--------+------+
| id | name | sid | cid | id | cname | tid |
+----+--------+------+------+------+--------+------+
| | 张三 | | | | 数学 | |
| | 李四 | | | | 数学 | |
| | 张三 | | | | 英语 | |
| | 张三 | | | | 语文 | |
| | 李四 | | | | 体育 | |
| | 初一 | | | | 体育 | |
| | 王二 | | | | 物理 | NULL |
| | 王二 | | | NULL | NULL | NULL |
| | 初二 | NULL | NULL | NULL | NULL | NULL |
+----+--------+------+------+------+--------+------+

用学生表连接中间表,再连接课程表可以得到结果。连接操作是针对两个表之间的,所以上面的结果是从左到右,两两连接得到的。

如果你有更多关于连接的问题,或者发现文章中的错误,欢迎留言交流

参考资料

《数据库系统概念》

03--SQLtie三言两语SQLtie链接(join)的更多相关文章

  1. 2018.03.27 python pandas merge join 使用

    #2.16 合并 merge-join import numpy as np import pandas as pd df1 = pd.DataFrame({'key1':['k0','k1','k2 ...

  2. 数据库 的几种链接 join

    直接demo,懒的同学可以看看效果 两个表的数据 join和inner join一样 full join报错,可有大神知道原因?

  3. 十几张表的join(千万级/百万级表) 7hours-->5mins

    ================START============================== 来了一个mail说是job跑得很慢,调查下原因 先来看下sql: SELECT h.order_ ...

  4. sort merge join导致temp被爆菊

    SQL_ID cqsz37256v36j, child number 1 ------------------------------------- INSERT /*+append*/ INTO T ...

  5. oracle相关的知识

    01.表空间的创建与删除 Spool 目录  (把sql语句都记录在txt文件中)spool  e:\xxx.txtSpool off 结束   SQL> --清除屏幕信息SQL> cle ...

  6. 013:Rank、视图、触发器、MySQL内建函数

    一. Rank 给出不同的用户的分数,然后根据分数计算排名 (gcdb@localhost) 09:34:47 [mytest]> create table t_rank(id int,scor ...

  7. 20170621_oracle练习

    ========================= 启动Oracle ========================= --->启动OracleOraDb11g_home1TNSListene ...

  8. .Netcore 2.0 Ocelot Api网关教程(4)- 服务发现

    本文介绍Ocelot中的服务发现(Service Discovery),Ocelot允许指定一个服务发现提供器,之后将从中寻找下游服务的host和port来进行请求路由.关于服务发现的详细介绍请点击. ...

  9. sql monitor生成不了报告& FFS hint不生效两个问题思考

    事情的发生就是这么偶然,一步步的深入才能汲取到更深入的知识~~ -------------------START------------------------------------------- ...

随机推荐

  1. POJ 1979 Red and Black (BFS)

    链接 : Here! 思路 : 简单的搜索, 直接广搜就ok了. /****************************************************************** ...

  2. 一步一步实现基于GPU的pathtracer(二):求交算法

    不管是哪种全局光照算法,最根本的都要落实到光线与物体的求交.主要分为光线与参数曲面和非参数曲面的求交,典型的参数曲面有球.盒.圆柱等基本体及基本体的组合体,以及一些更为复杂的参数曲面.非参数曲面就是所 ...

  3. 数据结构实验病毒感染检测问题(C++)

    医学研究者最近发现了某些新病毒,通过对这些病毒的分析,得知他们的DNA序列都是环状的.现在研究者已收集了大量的病毒DNA和人的DNA数据,想快速检测出这些人是否感染了相应的病毒.为了方便研究,研究者将 ...

  4. [luogu4159 SCOI2009] 迷路(矩阵乘法)

    传送门 Solution 矩阵乘法新姿势qwq 我们知道当边权为1是我们可以利用矩阵快速幂来方便的求出路径数 那么对于边权很小的时候,我们可以将每个点都拆成若干个点 然后就将边权不为1转化为边权为1了 ...

  5. 邓_ PHP·笔记(函数总结)

    PHP 指 PHP:超文本预处理器(译者注:PHP: Hypertext Preprocessor,递归命名) PHP 是一种服务器端的脚本语言,类似 ASP PHP 脚本在服务器上执行 PHP 支持 ...

  6. QT的creator中图示

    不同的开发工具显示class和相关的用不同的图标表示.但大同小异.但对于QT的creator中图示确实不太好分.看图一目了然.

  7. ASP用户登录代码

    asp+access用户登录代码,其中huiyuan.mdb数据库名pUser213 表名y_username用户名字段,y_password密码字段. login.htm页面<head> ...

  8. WinForm 登录窗体 + 单实例运行

    关于怎么在winform里增加登录窗体或者如何让winform程序单实例运行网上都很多例子. 然而两者结合起来呢? //Program.cs static class Program { public ...

  9. ACDream - Lowbit Sum

    先上题目: C - Lowbit Sum Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others ...

  10. 洛谷—— P2647 最大收益

    https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,……,n.你可以在这当中任意选择任意多个物品.其中第i个物 ...