1.SELECT语句的执行顺序是什么?
大纲
-
初步给出的答案是:
from(含join)->where->group by->having->select->distinct->order by->Limit/offset -
问题描述:
/**
1. 给出一张Mysql表的创建语句,然后给这张表插入20条数据(也给出对应的插入语句)
2. 然后查询这张表,要求用到以下所有关键字(一个关键字都不能少):
join->from->where->group by->having->select->distinct->order by->Limit/offset
*/ -
初步问题:
- 每一行要体现:这个部门有多少个员工,这个部门的平均工资是多少?
-
创建表
– 部门表
CREATE TABLE departments (
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL
);– 员工表:
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(50) NOT NULL,
dept_id INT,
salary DECIMAL(10,2),
hire_date DATE);
实现
1.初步思考
* 一个部门对应多个员工,所以员工表有个外键(OK)
* 部门是实实在在存在的,但是有的人是没有任何部门,例如保安不属于任何部门 => OK
* "这个部门有多少个员工,这个部门的平均工资是多少?"的理解:
- 研发部,5,13000
- 销售部,10,9000
* 如果我select * from部门? => 有个问题,有个保安不属于任何部门,在这个方向没有体现出来
- select * from departments left join employees
研发部,张三,7000
研发部,李四,8000
研发部,王五,9000
销售部,赵云,5000
销售部,张飞,6000
业务部,曹操,9000,
业务部,许褚,3000
- select * from departments left join employees 假如再来个 group by dept_id
研发部,3人,8000
销售部,2人,5500
业务部,2人,6000
* 语句要变了,不能select * 了,select * 只是便捷理解罢了
- select d.dept_id,d.dept_name from departments d left join employees e
on d.dept_id = e.dept_id group by dept_id #不过没有每个部门的人数
- select d.dept_id,d.dept_name,count(d.dept_id) as '人数' from departments d left join employees e
on d.dept_id = e.dept_id group by dept_id #现在还差,每个部门薪资的平均值
* mysql求平均值的方法
AVG(列名)
* 语句再次进化:
- select d.dept_id,d.dept_name,count(d.dept_id) as '人数',AVG(e.salary) from departments d left join employees e
on d.dept_id = e.dept_id group by dept_id #现在每个部门的平均工资也有了
* 如果我select * from 员工?
- select * from employees left join departments
张三,研发部,7000
李四,研发部,8000
王五,研发部,9000
赵云,销售部,5000
张飞,销售部,6000
曹操,业务部,9000
许褚,业务部,3000
- select * from employees left join departments 假如再来个 group by dept_id 可行?
3人,研发部,8000
2人,销售部,5500
2人,业务部,6000
* 语句要变了,不能select * 了,select * 只是便捷理解罢了
- select d.dept_id,d.dept_name from employees e left join departments d
on d.dept_id = e.dept_id group by dept_id #现在还少了人数
- select d.dept_id,d.dept_name,count(e.emp_id) as '人数' from employees e left join departments d
on d.dept_id = e.dept_id group by dept_id #现在还少了平均工资
- select d.dept_id,d.dept_name,count(e.emp_id) as '部门人数',AVG(e.salary) as '平均工资' from employees e left join departments d
on e.dept_id = d.dept_id group by dept_id #现在每个部门平均工资也有了
2.初步理解(OK)
* 看来select * from departments ..的思维 和 select * from employees 的思维还是有区别的,且这种区别是致命的!
- 为什么致命? 如果有人(假如保安)不属于任何部门,那么 select * from departments的思维就会把这个保安遗漏掉,而select * from employees 会拾起这个保安
- 为什么致命2? 如果有部门(春节留公司部)没有任何员工,那么 select * from employees的思维就会把这个部门遗漏
* 无论select * from departments ...思维还是select * from employees 思维,分组的时候,都是统一 group by 部门id
- 因为这是表与表之间的关系决定的!因为一个部门对应多个员工:
|--- 张三,
研发部 ---|--- 李四
|--- 王五
|--- 赵云,
销售部 ---|--- 张飞
|--- xx
从上面发现的规律,部门像root,而人像叶子,那么分组肯定以root分组
* 至于左连接on后面的 on d.dept_id = e.dept_id group 还是 on e.dept_id = d.dept_id;这两个写法是可以互相换位置,且不是致命操作;
3.“查询每个部门有多少人,每个部门的平均工资是多少”-左表是员工(OK)
* 初步sql语句:
select d.dept_name, count(e.emp_id) as '部门人数',AVG(e.salary) as '平均工资' from employees e left join departments d on e.dept_id = d.dept_id
GROUP BY d.dept_id
* 初步sql语句->group by 规范:
select d.dept_name, count(e.emp_id) as '部门人数',AVG(e.salary) as '平均工资' from employees e left join departments d on e.dept_id = d.dept_id
GROUP BY d.dept_id,d.dept_name
// 在标准 SQL 中,SELECT 子句中的非聚合字段(如 d.dept_name)必须出现在 GROUP BY 子句中,否则会报错。
// 是一种规范,dept_name很明显是非聚合字段,再说group by后面接聚合字段也不合理
* 初步sql语句->group by 规范查出来的视图:
/**
研发部 6 16333.333333
市场部 5 13000.000000
财务部 4 10750.000000
人事部 2 9250.000000
行政部 2 8650.000000
NULL 2 8000.000000
*/
* 初步sql语句->group by 规范->IFNULL 规范:
select IFNULL(d.dept_id,'无id'),IFNULL(d.dept_name,'无部门'),count(e.emp_id) as '部门人数',AVG(e.salary) as '平均工资'
from employees e left join departments d on e.dept_id = d.dept_id
group by d.dept_id,d.dept_name;
// IFNULL 相当于 备胎选择器,小白备胎选择器
/**
1 研发部 6 16333.333333
2 市场部 5 13000.000000
3 财务部 4 10750.000000
4 人事部 2 9250.000000
5 行政部 2 8650.000000
无id 无部门 2 8000.000000
*/
* select * from employees e left join departments d on e.dept_id = d.dept_id 的查询视图(from谁(表),谁(表)的信息就首先显示)
- 少了一个战狼部
/**
1 张三 1 15000.00 2020-03-15 1 研发部
2 李四 1 18000.00 2021-07-20 1 研发部
3 王五 2 12000.00 2019-11-10 2 市场部
4 赵六 1 16000.00 2020-05-25 1 研发部
5 孙七 2 13000.00 2021-02-14 2 市场部
6 周八 3 11000.00 2020-09-30 3 财务部
7 吴九 1 17000.00 2021-12-05 1 研发部
8 郑十 2 14000.00 2020-08-12 2 市场部
9 王十一 3 11500.00 2021-04-18 3 财务部
10 李十二 1 15500.00 2020-06-22 1 研发部
11 张十三 2 13500.00 2021-10-11 2 市场部
12 刘十四 3 10500.00 2020-03-01 3 财务部
13 陈十五 1 16500.00 2021-08-19 1 研发部
14 杨十六 2 12500.00 2020-07-07 2 市场部
15 黄十七 3 10000.00 2021-05-29 3 财务部
16 林十八 4 9000.00 2022-01-01 4 人事部
17 徐十九 4 9500.00 2022-02-02 4 人事部
18 蔡二十 5 8500.00 2022-03-03 5 行政部
19 郭廿一 5 8800.00 2022-04-04 5 行政部
20 曹廿二 8000.00 2022-05-05
21 李日飞 8000.00 2022-05-05
*/
5.“查询每个部门有多少人,每个部门的平均工资是多少”-左表是部门(OK)
* 初步sql语句->group by 规范:
select d.dept_id,d.dept_name,count(e.emp_id) as '部门人数',AVG(e.salary) as '平均工资' from departments d left join employees e on e.dept_id = d.dept_id
group by d.dept_id,d.dept_name
* 初步sql语句->group by 规范查出来的视图:
/**
1 研发部 6 16333.333333
2 市场部 5 13000.000000
3 财务部 4 10750.000000
4 人事部 2 9250.000000
5 行政部 2 8650.000000
6 战狼部 0 NULL
*/
* 初步sql语句->group by 规范->coalesce 规范:
select d.dept_id,d.dept_name,count(e.emp_id) as '部门人数', coalesce( AVG(e.salary),'无工资') as '平均工资'from departments d
left join employees e on e.dept_id = d.dept_id
group by d.dept_id,d.dept_name;
// coalesce是高级备胎选择器
/**
1 研发部 6 16333.333333
2 市场部 5 13000.000000
3 财务部 4 10750.000000
4 人事部 2 9250.000000
5 行政部 2 8650.000000
6 战狼部 0 无工资
*/
* select * from departments d left join employees e on e.dept_id = d.dept_id (from谁,谁先显示在前面)
- 少了两个人:曹廿二,李日飞
/**
1 研发部 1 张三 1 15000.00 2020-03-15
1 研发部 2 李四 1 18000.00 2021-07-20
2 市场部 3 王五 2 12000.00 2019-11-10
1 研发部 4 赵六 1 16000.00 2020-05-25
2 市场部 5 孙七 2 13000.00 2021-02-14
3 财务部 6 周八 3 11000.00 2020-09-30
1 研发部 7 吴九 1 17000.00 2021-12-05
2 市场部 8 郑十 2 14000.00 2020-08-12
3 财务部 9 王十一 3 11500.00 2021-04-18
1 研发部 10 李十二 1 15500.00 2020-06-22
2 市场部 11 张十三 2 13500.00 2021-10-11
3 财务部 12 刘十四 3 10500.00 2020-03-01
1 研发部 13 陈十五 1 16500.00 2021-08-19
2 市场部 14 杨十六 2 12500.00 2020-07-07
3 财务部 15 黄十七 3 10000.00 2021-05-29
4 人事部 16 林十八 4 9000.00 2022-01-01
4 人事部 17 徐十九 4 9500.00 2022-02-02
5 行政部 18 蔡二十 5 8500.00 2022-03-03
5 行政部 19 郭廿一 5 8800.00 2022-04-04
6 战狼部
*/
6.是count(d.dept)还是count(e.emp_id)的高级理解:(OK)
* 首先问题是:"查询每个部门有多少人,每个部门的平均工资是多少"
* 那是count(d.dept)决定每个分组多少人,还是count(e.emp_id)决定每个部门多少人?
- 现在思考count(d.dept)方向+select * from departments ..方向:
* select d.dept_name,count(d.dept_id) as '部门人数' from departments d left join employees e on d.dept_id = e.dept_id group by d.dept_id,d.dept_name
* 首先可以肯定的是,由于"from departments",departments是左表,说明departments的内容在left join之后会完整显示,部门一定不会落下
* 如果你以 count(d.dept_id) 作为部门人数,感觉不妥,理由是:假如一个部门没有任何员工,那么count(d.dept_id)恒等于1
* 此时.如果你以 count(e.emp_id) 作为部门人数,感觉还行,因为一个部门没有任何人,计算出来的count(e.emp_id)=0,很合理啊;
- 现在思考count(e.emp_id)方向+select * from employees 方法:
* select d.dept_name,count(e.emp_id) as '部门人数' from employees e left join departments d on d.dept_id = e.dept_id group by d.dept_id,d.dept_name
* 首先可以肯定的是,在left join后,employees的内容一定会完整显示
* 如果有人没有属于任何部门,那么这个人还是会被查出来的,关于部门的信息都对应是NULL,
* 由于 group by d.dept_id 属于强制按部门进行分组,那么NULL部门会分为一组,假如有两个人没有属于任何部门,那么NULL这一组会有两个记录,也就是说count(e.emp_id)=2,还能接收
* 此时,如果你换成 count(d.dept),那么count(d.dept)=0,感觉不是很合理,因为NULL这一组还是有两个人的
* 所以初步结论是:
你要查每个部门的人数是多少,始终使用count(e.emp_id)
7.无论是 left join departments 还是 left join employees 都会导致数据丢失的高级理解(OK)
* select * from employees e left join departments d on d.dept_id = e.dept_id
- 这条语句会导致部门丢失
* select * from departments d left join employees e on e.dept_id on d.dept_id
- 这条语句会导致员工丢失
* union和union all展望:
- union和union all会把两个表拼接(上下的方向)
- union会去重,union all不会去重(all表示我都要)
* 备胎选择器:IFNULL和coalesce
- IFNULL是小白备胎选择
- coalesce是大神备胎选择器
* 升级问题:
- 查询每个部门有多少人,每个部门的平均工资是多少,如果有部门没有人,平均工资给为0,如果有人不属于任何部门,那么显示'无部门'
* 初步sql语句:
select d.dept_name,count(e.emp_id) as '部门人数', IFNULL( AVG(e.salary),0) as '平均工资' from departments d left join employees e on e.dept_id = d.dept_id
group by d.dept_id,d.dept_name
union
select IFNULL(d.dept_name,'无部门'),count(e.emp_id) as '部门人数',AVG(e.salary) as '平均工资' from employees e left join departments d on d.dept_id = e.dept_id
group by d.dept_id,d.dept_name
/**
研发部 6 16333.333333
市场部 5 13000.000000
财务部 4 10750.000000
人事部 2 9250.000000
行政部 2 8650.000000
战狼部 0 0.000000
无部门 2 8000.000000
*/
* 初步sql语句有如下问题:
- union 会有去重操作,去重是降低效率的一个因素
- 并没有深刻理解问题的本质:
* 如果 from employees left join departments ,那么部门肯定会丢失,那么我第二个查询就怼丢失的部门找,那么 union 可以换成 union all
* 如果 from departments left join employees, 那么员工可能会丢失,那么同理第二个查询就怼着员工找
@使用union,怼着部门找
* 初步sql语句:
select coalesce(d.dept_name,'无部门'),count(e.emp_id) as '部门人数',AVG(e.salary) as '平均工资' from employees e left join departments d on d.dept_id = e.dept_id
group by d.dept_id,d.dept_name
union all
select d.dept_name,0 as '部门人数',0 as '平均工资' from departments d left join employees e on e.dept_id = d.dept_id where e.emp_id is null;
/**
研发部 6 16333.333333
市场部 5 13000.000000
财务部 4 10750.000000
人事部 2 9250.000000
行政部 2 8650.000000
无部门 2 8000.000000
战狼部 0 0.000000
*/
@使用union,怼着员工找:
* 初步sql语句:
select d.dept_name,count(e.emp_id) as '部门人数', coalesce(AVG(e.salary),0) as '平均工资' from departments d left join employees e on e.dept_id = d.dept_id
group by d.dept_id,d.dept_name
union all
select '无部门',count(e.emp_id) as '部门人数', AVG(e.salary) as '平均工资' from employees e left join departments d on d.dept_id = e.dept_id where d.dept_id is null
/**
研发部 6 16333.333333
市场部 5 13000.000000
财务部 4 10750.000000
人事部 2 9250.000000
行政部 2 8650.000000
战狼部 0 0.000000
无部门 2 8000.000000
*/
8.一条sql语句使用到所有"顺序词汇"(OK)
* 初步顺序:from(含join)->where->group by->having->select->distinct->order by->Limit/offset
* 初步的sql语句:
/**
select
distinct
d.dept_id, d.dept_name,count(e.emp_id) as department_count
from departments d left join employees e on e.dept_id = d.dept_id
where e.salary>10000
GROUP BY d.dept_id
having department_count>3
ORDER BY dept_id desc
limit 1
*/
* 初步理解:
- HAVING:对分组后的结果进行过滤
- SELECT:选择要返回的列
- distinct:后面跟列,如果是多列,那么就是组合列必须唯一(类似组合键的味道)