聚合函数作用于一组数据,并对一组数据返回一个值。

5大常用聚合函数

max (最大值)任意数据类型

  1. select max(salary)
  2. from employees;

min (最小值)任意数据类型

select min(salary)
       from employees;

sum (总和)数值型数据

select sum(salary)
       from employees;

avg (平均值)数值型数据

select avg(salary)
       from employees;

count

作用:计算指定字段在查询结构中出现的次数

select count(employee_id) from employees;

select count(employee_id),count(salary) from employees;

COUNT()返回表中记录总数,适用于任意数据类型
COUNT(expr) 返回expr不为空的记录总数。它不包含空值
COUNT(1) 返回*一行
的记录总数。

avg() = sum() / count()
需求:查询公司中的平均奖金率

#错误的
select avg(commission_pct) from employees;

#正确的
select sum(commission_pct)/count(ifnull(commission_pct,0)) from employees;
select avg(ifnull(commission_pct,0)) from employees;

count(1),count(),count(具体字段),哪个效率更高。
如果使用的是MyISAM 存储引擎,则三者效率相同,都是O(1)
如果使用的是InnoDB 存储引擎,则三者效率:COUNT(
) = COUNT(1)> COUNT(字段)

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;

#错误的!
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id;

结论1:SELECT中出现的非组函数的字段必须声明在GROUP BY 中。反之,GROUP BY中声明的字段可以不出现在SELECT中。
结论2:GROUP BY 声明在FROM后面、WHERE后面,ORDER BY 前面、LIMIT前面
结论3:MySQL中GROUP BY中使用WITH ROLLUP

SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id WITH ROLLUP;

使用 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;

having子句

  1. 行已经被分组。
    2. 使用了聚合函数。
    3. 满足HAVING 子句中条件的分组将被显示。
    4. HAVING 不能单独使用,必须要跟 GROUP BY 一起使用。

练习:查询各个部门中最高工资比10000高的部门信息

#错误的写法:
SELECT department_id,MAX(salary)
FROM employees
WHERE MAX(salary) > 10000
GROUP BY department_id;

要求1:如果过滤条件中使用了聚合函数,则必须使用HAVING来替换WHERE。否则,报错。
要求2:HAVING 必须声明在 GROUP BY 的后面。

正确的写法:

SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) > 10000;

要求3:开发中,我们使用HAVING的前提是SQL中使用了GROUP BY。

练习:查询部门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 可以使用分组中的计算函数 在最后的结果集中进行筛选,执行效率较低

开发中的选择:
WHERE 和 HAVING 也不是互相排斥的,我们可以在一个查询里面同时使用 WHERE 和 HAVING。包含分组统计函数的条件用 HAVING,普通条件用 WHERE。这样,我们就既利用了 WHERE 条件的高效快速,又发挥了 HAVING 可以使用包含分组统计函数的查询条件的优点。当数据量特别大的时候,运行效率会有很大的差别。

SQL底层执行原理

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 …,….

其中:
(1)from:从哪些表中筛选
(2)on:关联多表查询时,去除笛卡尔积
(3)where:从表中筛选的条件
(4)group by:分组依据
(5)having:在统计结果中再次筛选
(6)order by:排序
(7)limit:分页

关键字的顺序

SELECT … FROM ……. (LEFT / RIGHT)JOIN ….ON…….. WHERE … GROUP BY … HAVING … ORDER BY … LIMIT…

SQL语句的执行过程:

FROM …,…-> ON -> (LEFT/RIGNT JOIN) -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> ORDER BY -> LIMIT