本文介绍MySQL基本操作中的分组函数与分组查询操作,并用几个案例来具体说明,加深对分组查询的认知。
一、分组函数
1.功能
MySQL分组函数用作统计使用
,又称为聚合函数或统计函数或组函数
具体一点理解:给定一组值(如一个数据表),通过分组函数来获取某一个值
2.分类
sum 求和、avg 平均值、max 最大值 、min 最小值 、count 计算个数
3.特点总结
- sum、avg一般用于处理数值型(不能处理字符串类型与日期类型,处理日期类型无意义)
max、min、count可以处理任何类型(字符串、日期等,count计算非空个数) - 以上分组函数都忽略null值
- 可以和 distinct 搭配实现去重的运算
- count函数的介绍
一般使用count(*)用作统计行数 - 和分组函数一同查询的字段要求是group by后的字段
4.具体案例
- 分组函数参数支持的类型
//前两条查询语句没有意义,SUM和AVG函数一般用于处理数值类型
SELECT SUM(last_name) ,AVG(last_name) FROM employees;
SELECT SUM(hiredate) ,AVG(hiredate) FROM employees;
//字符串也能排序,可以求最大、最小值;COUNT函数计算非空字段的行数
SELECT MAX(last_name),MIN(last_name) FROM employees;
SELECT MAX(hiredate),MIN(hiredate) FROM employees;
SELECT COUNT(commission_pct) FROM employees;
SELECT COUNT(last_name) FROM employees;
- 以上分组函数都忽略null值
//在下面的语句中,AVG(commission_pct)和SUM(commission_pct)/35的结果相同,因为总共107条记录,其中有72条记录是没有奖金的
SELECT SUM(commission_pct) ,AVG(commission_pct),SUM(commission_pct)/35,SUM(commission_pct)/107 FROM employees;
//最大最小函数也忽略null值
SELECT MAX(commission_pct) ,MIN(commission_pct) FROM employees;
//COUNT函数忽略null值
SELECT COUNT(commission_pct) FROM employees;
SELECT commission_pct FROM employees;
- 可以和 distinct 搭配实现去重的运算
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;
- count函数详细介绍
//COUNT函数统计非null的行数
SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees; #只要有一个属性字段的值为非null,则count+1
SELECT COUNT(1) FROM employees; #在每一行前面加了个1,然后统计1的个数,就是统计行数,作用和COUNT(*)相同
SELECT COUNT(2) FROM employees;以及SELECT COUNT("任意字符串") FROM employees;效果都和COUNT(*)类似
效率问题分析:
MYISAM存储引擎下 ,COUNT( * )的效率高
INNODB存储引擎下,COUNT( * )和COUNT(1)的效率差不多,比COUNT(字符串)要高一些(要先判断该字符串的值是否为null)
- 和分组函数一同查询的字段有限制
//以下查询结果没有意义
SELECT AVG(salary),employee_id FROM employees; #解释一下AVG(salary)查出来是一个值,而employee_id查出来是很多值,最终显示的是一行数据,employee_id无论显示谁都没意义
//正确的用法,和分组函数一同查询的需要时GROUP BY后面的字段
SELECT AVG(salary),department_id FROM employees GROUP BY department_id;
二、分组查询
1.语法
select 分组函数, 列(该列出现在group by 的后面)
from 表
【where 筛选条件】
group by 分组的字段
【having 分组后筛选条件】
【order by 排序的字段】;
2.特点
- 和分组函数一同查询的字段必须是group by后出现的字段
- 分组查询中的筛选条件分为两类:分组前筛选和分组后筛选
分类 | 针对的表 | 位置 | 连接的关键字 |
分组前筛选 | 原始表 | group by前 | where |
分组后筛选 | group by后的结果集 | group by后 | having |
小结:
(1) 分组函数做筛选条件肯定是放在having子句中
(2) 一般来讲,能用分组前筛选的,尽量使用分组前筛选,提高效率
- 分组可以按单个字段也可以按多个字段分组(多个字段之间用逗号隔开,没有顺序要求),也可以按照表达式分组(用的较少)
- 可以搭配着排序使用,放在整个分组查询的最后
3.具体案例
- 简单分组
#案例1:查询每个工种的员工平均工资
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id;
#案例2:查询每个位置的部门个数
SELECT COUNT(*),location_id
FROM departments
GROUP BY location_id;
- 添加
分组前
的筛选条件
#案例1:查询邮箱中包含a字符的 每个部门的最高工资
SELECT MAX(salary),department_id
FROM employees
WHERE email LIKE '%a%'
GROUP BY department_id;
#案例2:查询有奖金的每个领导手下员工的平均工资
SELECT AVG(salary),manager_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY manager_id;
- 添加
分组后
的筛选条件
#案例:查询哪个部门的员工个数>5
# (1)查询每个部门的员工个数
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id;
#(2)筛选刚才(1)的结果
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>5; (这里不能把HAVING写成WHERE COUNT(*) > 5放在GROUP BY前面)
#案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT job_id,MAX(salary)
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING MAX(salary)>12000;
#案例3:领导编号>102的每个领导手下的最低工资大于5000的领导编号和最低工资
SELECT manager_id,MIN(salary)
FROM employees
WHERE manager_id > 102
GROUP BY manager_id
HAVING MIN(salary)>5000;
- 按
表达式或函数
分组
#案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些员工
SELECT COUNT(*),LENGTH(last_name)
FROM employees
GROUP BY LENGTH(last_name)
HAVING COUNT(*) > 5;
- 按
多个字段
分组
#案例:查询每个工种每个部门的最低工资,并按最低工资降序
SELECT MIN(salary),job_id,department_id
FROM employees
GROUP BY department_id,job_id
ORDER BY MIN(salary) DESC;
注意代码中分组字段的位置顺序可以任意,达到的每一个分组是一样的效果
- 添加
排序
#案例:每个工种有奖金的员工的最高工资>6000的工种编号和最高工资,按最高工资升序(可以给最高工资起别名)
SELECT job_id,MAX(salary) m
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING m>6000
ORDER BY m ;