MySQL-基础-多表查询
1. 多表关系
项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:
- 一对多(多对一)
- 多对多
- 一对一
1.1 一对多
案例: 部门 与 员工的关系
关系: 一个部门对应多个员工,一个员工对应一个部门
实现: 在多的一方建立外键,指向 一 的一方的主键

1.2 多对多
案例: 学生 与 课程 的关系
关系: 一个学生可以选修多门课程,一门课程也可以供多个学生选择
实现: 建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

1.3 一对一
案例: 用户 与 用户 详情的关系
关系: 一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率
实现: 在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)

2. 多表查询概述
2.1 执行sql脚本
1 | |
2.2 概述
多表查询就是指从多张表中查询数据。
2.2.1 笛卡尔积
笛卡尔乘积是指在数学中,两个集合 A 集合 和 B 集合的所有组合情况。
如果直接执行select * from emp , dept ; ,此时会将两个表的记录相乘。
但是在多表查询中,需要消除无效的笛卡尔积,只保留有效数据
正确姿势
1 | |
2.3 分类
连接查询
内连接:相当于查询A、B交集部分数据
外连接
- 左外连接:查询左表所有数据,以及两张表交集部分数据
- 右外连接:查询右表所有数据,以及两张表交集部分数据
自连接:当前表与自身的连接查询,自连接必须使用表别名
3. 内连接
内连接查询的是两张表交集部分的数据。
分为隐式内连接、显式内连接
3.1 语法
隐式内连接
1 | |
显式内连接
1 | |
4. 外连接
外连接分为两种,分别是:左外连接 和 右外连接。
4.1 语法
左外连接:左外连接相当于左表的所有数据,当然也包含表1和表2交集部分的数据。
1 | |
右外连接:右外连接相当于右表的所有数据,当然也包含表1和表2交集部分的数据。
1 | |
- 左外连接和右外连接是可以相互替换的,只需要调整在连接查询时SQL中,表结构的先后顺序就可以了。
- 而我们在日常开发使用时,更偏向于左外连接。
5. 自连接
5.1 自连接查询
顾名思义,就是自己连接自己,也就是把一张表连接查询多次。
5.1.1 语法
1 | |
对于自连接查询,可以是内连接查询,也可以是外连接查询。
在自连接查询中,必须要为表起别名,要不然我们不清楚所指定的条件、返回的字段,到底是哪一张表的字段。
5.2 联合查询
对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。
5.2.1 语法
1 | |
- 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
- union all 会将全部的数据直接合并在一起,union 会对合并之后的数据去重。
6. 子查询
6.1 概述
SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。
6.1.1 语法
1 | |
6.1.2 分类
根据子查询结果不同,分为:
- 标量子查询(子查询结果为单个值)
- 列子查询(子查询结果为一列)
- 行子查询(子查询结果为一行)
- 表子查询(子查询结果为多行多列)
根据子查询位置,分为:
- WHERE之后
- FROM之后
- SELECT之后
6.2 标量子查询
子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。
常用的操作符:= <> > >= < <=
6.3 列子查询
子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。

6.4 行子查询
子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。
常用的操作符:= 、<> 、IN 、NOT IN
6.5 表子查询
子查询返回的结果是多行多列,这种子查询称为表子查询。
常用的操作符:IN
7. 案例
7.1 数据准备
涉及到的表就三张:emp员工表、dept部门表、salgrade薪资等级表。
1 | |
查询员工的姓名、年龄、职位、部门信息
1
select emp.name,age,job,dept.name from emp,dept where emp.dept_id = dept.id;查询年龄小于30岁的员工的姓名、年龄、职位、部门信息
1 | |
查询拥有员工的部门ID、部门名称
1
2#distinct 去掉重复数据
select distinct dept.id,dept.name from emp,dept where emp.dept_id = dept.id;查询所有年龄大于40岁的员工, 及其归属的部门名称; 如果员工没有分配部门, 也需要展示出来
1
2
3
4#如果在外连接需要在加条件,就在on后面的条件接上where,然后输入新的条件
#如果把where改成and,会显示不全
#因为使用where,可以跳出左外连接的限制;而使用and,依然在左外连接之内,会显示左表所有
select e.*,d.name from emp e left join dept d on d.id = e.dept_id where e.age > 40;查询所有员工的工资等级
1
select emp.*,grade from emp,salgrade where emp.salary >= salgrade.losal and emp.salary <= salgrade.hisal;查询“研发部”所有员工的信息以及工资等级
1
select emp.*,grade from emp,salgrade,dept where (emp.salary between salgrade.losal and salgrade.hisal) and emp.dept_id = dept.id and dept.name = '研发部';查询 “研发部” 员工的平均工资
1
select avg(e.salary) from emp e,dept d where e.dept_id = d.id and d.name = '研发部';查询工资比 “灭绝” 高的员工信息。
1
select * from emp e where salary >(select salary from emp e where e.name = '灭绝');查询比平均薪资高的员工信息
1
select * from emp e where salary >(select avg(salary) from emp e);查询低于本部门平均工资的员工信息
1
select * from emp where salary < (select avg(salary) from emp e ,dept d where e.dept_id = d.id and d.name='研发部');查询所有的部门信息,并统计部门的员工人数
1
select id,name,(select count(*) from emp e where e.dept_id = d.id) from dept d;查询所有学生的选课情况, 展示出学生名称, 学号, 课程名称
1
select s.name , s.no , c.name from student01 s , student_course sc , course01 c where s.id = sc.studentid and sc.courseid = c.id ;