本文将从连接的理论和语法讲起,结合具体的例子,详细分析 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. 文件元数据、文件夹操作(day08)

    一.获取文件的元数据(meta data) 通过read write可以对文件的内容进行读写. 但是今天我们要操作的是文件的元数据(文件的属性信息) day08$ls -l hello -rw-rw- ...

  2. 洛谷P1012 拼数【字符串+排序】

    设有nn个正整数(n≤20)(n≤20),将它们联接成一排,组成一个最大的多位整数. 例如:n=3n=3时,33个整数1313,312312,343343联接成的最大整数为:3433121334331 ...

  3. oracle到mysql的导数据方式(适用于任意数据源之间的互导)

    http://www.wfuyu.com/Internet/19955.html 为了生产库释放部份资源, 需要将API模块迁移到mysql中,及需要导数据. 尝试了oracle to mysql工具 ...

  4. [bzoj3307]雨天的尾巴_线段树合并

    雨天的尾巴 bzoj-3307 题目大意:N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. ...

  5. 用Thinphp发送电子邮件的方法

    好长时间没有动php了,突然想用thinkphp发送电子邮件,可是查阅了书籍都写的非常乱.没有继续看下去.这里找到了一个比較好的方法: 第一步:首先我们要引入一个外部类库:Mail.class.php ...

  6. C++管理指针成员

    1.C++中一般採用以下三种方法之中的一个管理指针成员: (1)指针成员採取常规行为. 这种类具有指针的全部缺陷:具有指针成员且使用默认复制构造函数和赋值操作符,无法避免悬垂指针(两个对象的指针成员指 ...

  7. S 禁止F12和右键操作控制台,兼容各浏览器

    document.oncontextmenu = function () { return false; };         document.onkeydown = function () {   ...

  8. ioctl方法详解

    设备控制接口(ioctl 函数)回想一下我们在字符设备驱动中介绍的struct file_operations 结构,这里我们将介绍一个新的方法: int (*ioctl) (struct inode ...

  9. tiny4412开机动画、开机界面的定制 【原创】

    关键词:Android  linux 开机logo 开机动画  平台信息:内核:linux3.0.68 系统:android/android5.1平台:tiny4412 作者:庄泽彬(欢迎转载,请注明 ...

  10. poj--1664--放苹果(递归好体)

    放苹果 Time Limit: 1000MS   Memory Limit: 10000KB   64bit IO Format: %I64d & %I64u Submit Status De ...