SELECT语句的执行顺序是什么

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:后面跟列,如果是多列,那么就是组合列必须唯一(类似组合键的味道)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值