SQL 自学笔记(5)多表查询
多表查询
本文笔记根据【b站 尚硅谷-宋红康 MySQL 课程】整理。笔记和代码存储在我的 GitHub 库中 github.com/isKage/sql-notes。
多表查询,关联查询,指对多个表进行查询。
前提:被查询的多表之间存在联系,即存在关键字段、相同字段(例如:外键)
1 笛卡尔积
1.1 错误的查询
如果直接查询,则会出现笛卡尔积错误。
1 | SELECT last_name, department_name |
1 | SELECT COUNT(last_name) FROM employees; -- 107 rows |
即将两个表的所有行进行了组合,将所有非重复组合一同输出。
1.2 笛卡尔积
定义:对于集合 $A,\ B$ 称由 $A,\ B$ 则称 $A$ 和 $B$ 的笛卡尔积是 $A$ 和 $B$ 的所有可能组合。
则容易得知新的集合元素个数为 $|A| \times |B|$ ,其中 $|\cdot|$ 表示元素个数。
1.3 CROSS JOIN
交叉连接
笛卡尔积也称为交叉连接,可以使用 CROSS JOIN
INNER JOIN
JOIN
链接二表。
1 | SELECT last_name, department_name |
不通过
WHERE
或ON
添加条件,则会出现笛卡尔积错误
1.4 WHERE
加入链接条件
为了避免笛卡尔积, 可以在 WHERE
加入有效的连接条件。格式为
1 | SELECT 表1.列名, 表1.列名 |
- 例:根据部门 id 筛选
1 | # WHERE 加入条件 |
在表中有相同列时,在列名之前加上表名前缀。【推荐使用,方便标注各表各列】
2 多表查询概念
2.1 等值连接 & 非等值连接
2.1.1 键的类型
主键
PRI
& 唯一标识UNI
& 外键MUL
在SQL中,key
是用于标识表中列的属性,常见的类型包括 PRI
、MUL
和 UNI
。这些属性描述了列在表中的角色和约束。以下是它们的详细区别:
PRI
(Primary Key):表示该列为表的主键。
值唯一,不能有重复;不为空;唯一标识;可作为唯一索引;
UNI
(Unique Key):表示该列具有唯一约束。
值唯一,不能有重复;允许空值;也可作为唯一索引;
MUL
(Multiple):表示该列是外键或普通索引。
非唯一性,值可以重复;如果该列是外键,它引用另一个表的主键或唯一键;
使用 DESC
查询表的属性
1 | DESC employees; |
2.1.2 等值连接
一般通过外键寻找另一个表的唯一索引(PRI
或 UNI
)
1 | -- 根据 job_id 外键连接 jobs 表的 job_title |
- 多个条件
AND
连接
1 | SELECT employees.last_name, departments.department_name, employees.department_id |
- 多个表中有相同列时,必须在列名之前加上表名前缀
【推荐使用,方便标注各表各列,提高查询效率】
- 使用别名可以简化查询
1 | SELECT e.last_name, d.department_name, e.department_id |
一但使用了别名,这一个语句中必须使用别名替代
- 连接多个表
例如:展示员工 last_name, department_name, city
1 | SELECT e.last_name, d.department_name, lc.city |
连接 N 个表,至少需要 N-1 个条件
2.1.3 非等值连接
1 | SELECT e.last_name, e.salary, j.grade_level AS GRADE |
2.2 自连接 & 非自连接
使用别名的方式把 1 张表虚拟成 2 张表,而后两表可以进行内连接和外连接
1 | SELECT CONCAT(worker.last_name, ' works for ' |
将 employees 表虚拟为 表 worker 和 manager,然后自连接
2.3 内连接 & 外连接
- 内连接:合并的表存在联系,即存在相同列。结果中不包含一个表与另一个表不匹配的行
内连接使用 INNER JOIN
- 外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回不满足条件的行
外连接使用 LEFT JOIN
RIGHT JOIN
,特别地,对 MySQL 而言全外连接需要使用 UNION
方法
不满足条件的行 —— 相应的列为空
NULL
当返回不满足条件的行来自左表时,则为左外连接,左边的表也称为主表 ,右边的表称为从表
当返回不满足条件的行来自右表时,则为右外连接,右边的表也称为主表 ,左边的表称为从表
3 多表查询代码
使用 SQL99
语法实现
3.1 基础语法 JOIN ON
标准格式
1 | SELECT table1.column, |
- 各个条件相互独立
- 使用
JOIN
CROSS JOIN
INNER JOIN
含义相同,均代表内连接
下面看具体内连接案例:
3.2 内连接
1 | SELECT table1.column, |
- 例:查询
last_name, department_name, city
员工为'Chen'
1 | SELECT e.last_name, d.department_name, lc.city |
3.3 外连接
3.3.1 左外连接 LEFT JOIN ON
1 | -- A 为主表,B 表向 A 表插入 |
- 例:
employees
表中Grant
对应department_id
为NULL
故在表departments
检索不到
1 | SELECT e.last_name, e.department_id, d.department_name |
3.3.2 右外连接 RIGHT JOIN ON
1 | -- B 为主表,A 表向 B 表插入 |
- 例:
employees
表中没有处于departments
表中Treasury
部门的,故向departments
插入时补空
1 | SELECT d.department_name, e.last_name, e.department_id |
3.3.3 满外连接 FULL JOIN ON
1 | 满外连接的结果 = 左右表匹配到的数据 + 左表没有匹配到的数据 + 右表没有匹配到的数据 |
标准语法
1 | -- 互相charity |
注:
MySQL
不支持FULL JOIN
,但可以通过合并左外连接和右外连接的方式实现。可以简单理解:
FULL JOIN <=> LEFT JOIN UNION RIGHT JOIN
4 合并查询结果 UNION
UNION
可以将多个 SELECT 语句得到的结果合并成一个表输出:
- 匹配:多个 SELECT 语句得到的结果集列数和数据类型必须相同
- 去重与否:使用
UNION
会去除重复数据;使用UNION ALL
不会去除重复数据
1 | SELECT column, ... FROM table1 |
- 例:查询部门编号
department_id > 90
或 邮箱email
包含a
的员工信息
1 | -- 法一:使用 WHERE |
5 JOIN 实现的几种关系(总结)
5.1 内连接:A 交 B
A 表与 B 表内连接,相当于 $A \cap B$
1 | SELECT A.column, B.column |
5.2 左外连接:A 交 (A 交 B)
A 表作为主表,B 表作为从表插入 A ,相当于 $A + A \cap B$
1 | SELECT A.column, B.column |
5.3 右外连接:B 交 (A 交 B)
B 表作为主表,A 表作为从表插入 B ,相当于 $B + A \cap B$
1 | SELECT A.column, B.column |
左外连接和右外连接本质相同
5.4 WHERE 找出空值 IS NULL:只属于 A
A 表作为主表,B 表插入,但去除完美匹配的,即 A 表中与 B 表无关的部分。相当于 $A - A \cap B$
1 | SELECT A.column, B.column |
- 例:查询 部门表中无员工的部门
1 | SELECT d.department_name, d.department_id, e.department_id |
5.5 UNION 合并:A 并 B
UNION 可以将多个 SELECT 语句得到的结果合并成一个表输出,相当于 $A \cup B$
1 | SELECT column, ... |
- 例:两张方法,推荐第一种【先手动去重,再使用 UNION ALL 效率高】
1 | -- 法一:利用 WHERE d.department_id IS NULL 手动去重 |
5.6 找出空值后 UNION 合并:对称差
查询所有匹配失败的行数据,相当于 $A \cup B - A \cap B$
1 | SELECT column, ... |
- 例:查询所有失败行数据
1 | SELECT employee_id, last_name, department_name |
6 特殊等值连接
6.1 自然连接
NATURAL JOIN
会自动查询两张表中所有相同的字段,然后进行等值连接
1 | -- 这是 SQL99 新语法 |
注:自然连接使用
AND
连接各个条件。即只有当所有相同列名的值都相等时,才会放入结果集。例如:当表 employees 和表 departments 有相同列 department_id 和 manager_id 时
1 | -- 上面自然连接等价于 |
6.2 USING 连接
当有多个同名字段时,USING
可以指定同名字段进行连接
1 | SELECT employee_id, last_name, department_name |
6.3 总结:等值连接的三种写法
1 | -- 法一:WHERE 限制条件 |
WHERE
的使用没有限制,目的就是增加约束条件ON
只能和JOIN
连用USING
只能和JOIN
,且要求字段必须同名