三言两语:SQL 连接(join)

前言

本文将从连接的理论和语法讲起,结合具体的例子,详细分析 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   |
+----+--------+
|  1 | 张三   |
|  2 | 李四   |
|  3 | 王二   |
|  4 | 初一   |
|  5 | 初二   |
+----+--------+

teacher

+----+-----------+
| id | name      |
+----+-----------+
|  1 | 王老师    |
|  2 | 李老师    |
|  3 | 张老师    |
|  4 | 肖老师    |
|  5 | NULL      |
|  6 | 陈老师    |
+----+-----------+

course

+----+--------+------+
| id | cname  | tid  |
+----+--------+------+
|  1 | 数学   |    1 |
|  2 | 英语   |    2 |
|  3 | 语文   |    3 |
|  4 | 体育   |    1 |
|  5 | 物理   | NULL |
+----+--------+------+

student_course

+-----+-----+
| sid | cid |
+-----+-----+
|   1 |   1 |
|   1 |   2 |
|   1 |   3 |
|   2 |   1 |
|   2 |   4 |
|   3 |   5 |
|   3 |   6 |
|   4 |   4 |
+-----+-----+

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

内连接teacher course的结果

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

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

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

左连接teacher course的结果

select * from teacher left join course on teacher.id = course.tid;
+----+-----------+------+--------+------+
| id | name      | id   | cname  | tid  |
+----+-----------+------+--------+------+
|  1 | 王老师    |    1 | 数学   |    1 |
|  2 | 李老师    |    2 | 英语   |    2 |
|  3 | 张老师    |    3 | 语文   |    3 |
|  1 | 王老师    |    4 | 体育   |    1 |
|  4 | 肖老师    | NULL | NULL   | NULL |
|  5 | NULL      | NULL | NULL   | NULL |
|  6 | 陈老师    | 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  |
+------+-----------+------+--------+------+
|    1 | 王老师    |    1 | 数学   |    1 |
|    2 | 李老师    |    2 | 英语   |    2 |
|    3 | 张老师    |    3 | 语文   |    3 |
|    1 | 王老师    |    4 | 体育   |    1 |
|    4 | 肖老师    | NULL | NULL   | NULL |
|    5 | NULL      | NULL | NULL   | NULL |
|    6 | 陈老师    | NULL | NULL   | NULL |
|    4 | 肖老师    |    4 | 体育   |    1 |
|    5 | NULL      |    5 | 物理   | 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  |
+----+--------+------+------+------+--------+------+
|  1 | 张三   |    1 |    1 |    1 | 数学   |    1 |
|  2 | 李四   |    2 |    1 |    1 | 数学   |    1 |
|  1 | 张三   |    1 |    2 |    2 | 英语   |    2 |
|  1 | 张三   |    1 |    3 |    3 | 语文   |    3 |
|  2 | 李四   |    2 |    4 |    4 | 体育   |    1 |
|  4 | 初一   |    4 |    4 |    4 | 体育   |    1 |
|  3 | 王二   |    3 |    5 |    5 | 物理   | NULL |
|  3 | 王二   |    3 |    6 | NULL | NULL   | NULL |
|  5 | 初二   | NULL | NULL | NULL | NULL   | NULL |
+----+--------+------+------+------+--------+------+

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

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

参考资料
《数据库系统概念》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342