3.2 使用多个列分组
# 查询各个(department_id, job_id)的平均工资 SELECT department_id, job_id, AVG(salary) FROM employees GROUP BY department_id, job_id;
分组的字段可以调换顺序,结果一致。
最后结果都为(department_id, job_id)一样的为同一组,只是分组的顺序不一样,一个先根据部门分组再根据工作分组,一个根据工作分组再根据部门分组,最终显示的结果一样。
# 查询各个(job_id, department_id)的平均工资 SELECT job_id, department_id, AVG(salary) FROM employees GROUP BY job_id, department_id;
3.3 结论
- 结论1:
SELECT中出现的非组函数的字段必须声明在GROUP BY 中。反之,GROUP BY中声明的字段可以不出现在SELECT中。 - 结论2:
GROUP BY 声明在FROM后面、WHERE后面,ORDER BY 前面、LIMIT前面
3.4 WITH ROLLUP
MySQL中GROUP BY中使用WITH ROLLUP,在所有查询出的分组记录之后增加一条记录,该记录是对所有组在进行一次统计,比如计算每组的平均工资,WITH ROLLUP新加的记录会计算每组合起来总的平均工资,即公司的平均工资。
SELECT department_id,AVG(salary) FROM employees GROUP BY department_id WITH ROLLUP;
注意:
当使用ROLLUP时,不能同时使用ORDER BY子句进行结果排序,即ROLLUP和ORDER BY是互相排斥的。
MySQL8.0,不报错,WITH ROLLUP新加记录也会参与排序
SELECT department_id,AVG(salary) avg_sal FROM employees GROUP BY department_id WITH ROLLUP ORDER BY avg_sal ASC;
4. HAVING
4.1 HAVING 的使用
HAVING子句用于过滤分组之后的数据。
1、如果过滤条件中使用了聚合函数,或行已经被分组,则必须使用HAVING来替换WHERE。否则,报错。
2、HAVING 必须声明在 GROUP BY 的后面。
# 查询各个部门中最高工资大于10000的部门信息 SELECT department_id, MAX(salary) max_salary FROM employees GROUP BY department_id # 对分组后的数据进行筛选,选出部门中最高工资大于10000的部门 HAVING max_salary > 10000;
开发中,我们使用HAVING的前提是SQL中使用了GROUP BY。
如果没有使用GROUP BY,使用HAVING,则整个表中的所有记录会被当成一组,然后对这一组记录根据HAVING中的条件进行筛选。
SELECT department_id, MAX(salary) max_salary FROM employees HAVING max_salary > 10000;
HAVING 不能单独使用,必须要跟 GROUP BY 一起使用。
# 查询部门id为10,20,30,40这4个部门中最高工资比10000高的部门信息 SELECT department_id, MAX(salary) max_salary FROM employees WHERE department_id in (10, 20, 30, 40) GROUP BY department_id HAVING max_salary > 10000;
# 查询部门id为10,20,30,40这4个部门中最高工资比10000高的部门信息 SELECT department_id, MAX(salary) max_salary FROM employees GROUP BY department_id # 对记录进行分组后,筛选出部门id为10, 20, 30, 40的组 HAVING department_id in (10, 20, 30, 40) AND max_salary > 10000;
1、当过滤条件中有聚合函数时,则此过滤条件必须声明在HAVING中。
2、当过滤条件中没有聚合函数时,则此过滤条件声明在WHERE中或HAVING中都可以。但是,建议大家声明在WHERE中。
上述两种方式,方式一的执行效率高于方式二,即WHERE的效率会高于HAVING。
4.2 HAVING 与 WHERE 的对比
- 从适用范围来讲,HAVING 的使用范围更广。
- 如果过滤条件中没有聚合函数:这种情况下,WHERE的执行效率要高于HAVING。
- WHERE会先过滤掉无用的数据,然后对过滤后的数据进行分组筛选操作,分组筛选操作的数据数小;而HAVING是先对所有的数据进行分组筛选,操作的数据数大,所以WHERE的执行效率要高于HAVING。
5. SELECT 的执行过程
5.1 SELECT 语句的完整结构
#sql92语法: SELECT ...., ...., ....(存在聚合函数) FROM ..., ...., .... WHERE 多表的连接条件 AND 不包含聚合函数的过滤条件 GROUP BY ..., .... HAVING 包含聚合函数的过滤条件 ORDER BY ...., ...(ASC / DESC ) LIMIT ..., ....
#sql99语法: SELECT ...., ...., ....(存在聚合函数) FROM ... (LEFT / RIGHT)JOIN ....ON 多表的连接条件 (LEFT / RIGHT)JOIN ... ON .... WHERE 不包含聚合函数的过滤条件 GROUP BY ..., .... HAVING 包含聚合函数的过滤条件 ORDER BY ...., ...(ASC / DESC ) LIMIT ..., ....