聚合函数介绍
聚合(或聚集、分组)函数,它是对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值。
AVG和SUM函数
AVG / SUM :只适用于数值类型的字段(或变量)
SELECT AVG ( salary) , SUM ( salary) , AVG ( salary) * 107
FROM employees;
如下的操作没有意义
SELECT SUM ( last_name) , AVG ( last_name) , SUM ( hire_date)
FROM employees;
MIN和MAX函数
MAX / MIN :适用于数值类型、字符串类型、日期时间类型的字段(或变量)
SELECT MAX ( salary) , MIN ( salary)
FROM employees;
SELECT MAX ( last_name) , MIN ( last_name) , MAX ( hire_date) , MIN ( hire_date)
FROM employees;
COUNT函数
作用:计算指定字段在查询结构中出现的个数(不包含NULL 值的)
SELECT COUNT ( employee_id) , COUNT ( salary) , COUNT ( 2 * salary) , COUNT ( 1 ) , COUNT ( 2 ) , COUNT ( * )
FROM employees ;
如果计算表中有多少条记录,如何实现?
方式1 :COUNT ( * )
方式2 :COUNT ( 1 )
方式3 :COUNT ( 具体字段) : 不一定对!
COUNT ( expr) 返回expr不为空的记录总数。
如何需要统计表中的记录数,使用COUNT ( * ) 、COUNT ( 1 ) 、COUNT ( 具体字段) 哪个效率更高呢?
如果使用的是MyISAM 存储引擎,则三者效率相同,都是O( 1 )
如果使用的是InnoDB 存储引擎,则三者效率:COUNT ( * ) = COUNT ( 1 ) > COUNT ( 字段)
问题:用count ( * ) ,count ( 1 ) ,count ( 列名) 谁好呢?
其实,对于MyISAM引擎的表是没有区别的。这种引擎内部有一计数器在维护着行数。
Innodb 引擎的表用count ( * ) , count ( 1 ) 直接读行数,复杂度是O( n) ,因为innodb 真的要去数一遍。但好
于具体的count ( 列名) 。
问题:能不能使用count ( 列名) 替换count ( * ) ?
不要使用 count ( 列名) 来替代 count ( * ) , count ( * ) 是 SQL92 定义的标准统计行数的语法,跟数
据库无关,跟 NULL 和非 NULL 无关。
说明:count ( * ) 会统计值为 NULL 的行,而 count ( 列名) 不会统计此列为 NULL 值的行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
group by
基本使用
查询各个部门的平均工资,最高工资
SELECT department_id, AVG ( salary) , SUM ( salary)
FROM employees
GROUP BY department_id
查询各个job_id的平均工资
SELECT job_id, AVG ( salary)
FROM employees
GROUP BY job_id;
使用多个列分组
查询各个department_id, job_id的平均工资
方式1 :
SELECT department_id, job_id, AVG ( salary)
FROM employees
GROUP BY department_id, job_id;
方式2 :
SELECT job_id, department_id, AVG ( salary)
FROM employees
GROUP BY job_id, department_id;
GROUP BY中使用WITH ROLLUP
使用 WITH ROLLUP 关键字之后,在所有查询出的分组记录之后增加一条记录,该记录计算查询出的所
有记录的总和,即统计记录数量
SELECT department_id, AVG ( salary)
FROM employees
GROUP BY department_id WITH ROLLUP ;
查询各个部门的平均工资,按照平均工资升序排列
SELECT department_id, AVG ( salary) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal ASC ;
当使用ROLLUP时,不能同时使用ORDER BY 子句进行结果排序,即ROLLUP和ORDER BY 是互相排斥的。
错误的:
SELECT department_id, AVG ( salary) avg_sal
FROM employees
GROUP BY department_id WITH ROLLUP
ORDER BY avg_sal ASC ;
小结
结论1 :SELECT 中出现的非组函数的字段必须声明在GROUP BY 中。
反之,GROUP BY 中声明的字段可以不出现在SELECT 中。
结论2 :GROUP BY 声明在FROM 后面、WHERE 后面,ORDER BY 前面、LIMIT 前面
HAVING(作用:用来过滤数据的)
要求1 :如果过滤条件中使用了聚合函数,则必须使用HAVING 来替换WHERE 。否则,报错。
要求2 :HAVING 必须声明在 GROUP BY 的后面。
要求3 :开发中,我们使用HAVING 的前提是SQL 中使用了GROUP BY
SELECT department_id, MAX ( salary)
FROM employees
GROUP BY department_id
HAVING MAX ( salary) > 10000 ;
查询部门id为10 , 20 , 30 , 40 这4 个部门中最高工资比10000 高的部门信息
方式1 :推荐,执行效率高于方式2.
SELECT department_id, MAX ( salary)
FROM employees
WHERE department_id IN ( 10 , 20 , 30 , 40 )
GROUP BY department_id
HAVING MAX ( salary) > 10000 ;
方式2 :
SELECT department_id, MAX ( salary)
FROM employees
GROUP BY department_id
HAVING MAX ( salary) > 10000 AND department_id IN ( 10 , 20 , 30 , 40 ) ;
结论:当过滤条件中有聚合函数时,则此过滤条件必须声明在HAVING 中。
当过滤条件中没有聚合函数时,则此过滤条件声明在WHERE 中或
HAVING 中都可以。但是,建议大家声明在WHERE 中。
WHERE 与 HAVING 的对比
1. 从适用范围上来讲,HAVING 的适用范围更广。
2. 如果过滤条件中没有聚合函数:这种情况下,WHERE 的执行效率要高于HAVING
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
SELECT的执行过程
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 . . . , . . . .
SQL 语句的执行过程:
FROM . . . , . . . - > ON - > ( LEFT / RIGNT JOIN ) - > WHERE - > GROUP BY - > HAVING - > SELECT - >
DISTINCT - > ORDER BY - > LIMIT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
聚合函数练习
1.where子句可否使用组函数进行过滤?
NO
2.查询公司员工工资的最大值,最小值,平均值,总和
SELECT MAX ( salary) , MIN ( salary) , AVG ( salary) , SUM ( salary)
FROM employees;
3.查询各job_id的员工工资的最大值,最小值,平均值,总和
SELECT job_id, MAX ( salary) , MIN ( salary) , AVG ( salary) , SUM ( salary)
FROM employees
GROUP BY job_id;
4.选择具有各个job_id的员工人数
SELECT job_id, COUNT ( * )
FROM employees
GROUP BY job_id;
5. 查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT MAX ( salary) , MIN ( salary) , MAX ( salary) - MIN ( salary) DIFFERENCE
FROM employees;
6.查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
SELECT manager_id, MIN ( salary)
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING MIN ( salary) > 6000 ;
7.查询所有部门的名字,location_id,员工数量和平均工资,并按平均工资降序
SELECT department_name, location_id, COUNT ( employee_id) , AVG ( salary) avg_sal
FROM employees e RIGHT JOIN departments d
ON e. ` department_id` = d. ` department_id`
GROUP BY department_name, location_id
ORDER BY avg_sal DESC ;
8.查询每个工种、每个部门的部门名、工种名和最低工资
SELECT department_name, job_id, MIN ( salary)
FROM departments d LEFT JOIN employees e
ON e. ` department_id` = d. ` department_id`
GROUP BY department_name, job_id