【MySQL】聚合函数

发布时间:2024年01月15日


聚合函数是什么?

聚合(或聚集、分组)函数,它是对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值。

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

  • 聚合函数类型

    • AVG()
    • SUM()
    • MAX()
    • MIN()
    • COUNT()
  • 聚合函数语法
    1

  • 聚合函数不能嵌套调用。

    • 比如不能出现类似“AVG(SUM(字段名称))”形式的调用。

一、AVG和SUM函数

AVG / SUM :只适用于数值类型的字段(或变量)

SELECT AVG(salary),MAX(salary),MIN(salary),SUM(salary)
FROM employees;

二、MIN和MAX函数

MAX / MIN :适用于数值类型、字符串类型、日期时间类型的字段(或变量)

SELECT MAX(last_name),MIN(last_name),MAX(hire_date),MIN(hire_date)
FROM employees;

1

三、COUNT函数

  • COUNT(*)返回表中记录总数,适用于任意数据类型
SELECT COUNT(*)
FROM employees

1

  • COUNT(expr) 返回expr不为空的记录总数。
SELECT COUNT(commission_pct)
FROM employees;

2

#如果计算表中有多少条记录,如何实现?
#方式1:COUNT(*)
#方式2:COUNT(1)
#方式3:COUNT(具体字段) : 不一定对!-> 不会计数为Null数据

SELECT COUNT(employee_id),COUNT(salary),COUNT(2 * salary),COUNT(1),COUNT(2),COUNT(*),COUNT(commission_pct)
FROM employees ;

3

#公式:AVG = SUM / COUNT
SELECT AVG(salary),SUM(salary)/COUNT(salary),
AVG(commission_pct),SUM(commission_pct)/COUNT(commission_pct),
SUM(commission_pct) / 107
FROM employees;
#需求:查询公司中平均奖金率
#错误的!
SELECT AVG(commission_pct)
FROM employees;

#正确的:
SELECT SUM(commission_pct) / COUNT(IFNULL(commission_pct,0)),
AVG(IFNULL(commission_pct,0))
FROM employees;

如何需要统计表中的记录数,使用COUNT()、COUNT(1)、COUNT(具体字段) 哪个效率更高呢?*

如果使用的是MyISAM 存储引擎,则三者效率相同,都是O(1)
如果使用的是InnoDB 存储引擎,则三者效率:COUNT(*) = COUNT(1)> COUNT(字段)

四、GROUP BY

1. 基本使用

可以使用GROUP BY子句将表中的数据分成若干组

SELECT column, group_function(column)
FROM table
[WHERE	condition]
[GROUP BY	group_by_expression]
[ORDER BY	column];

明确:WHERE一定放在FROM后面

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

1
包含在 GROUP BY 子句中的列不必包含在SELECT 列表中

SELECT   AVG(salary)
FROM     employees
GROUP BY department_id ;

1

2. 使用多个列分组

SELECT   department_id dept_id, job_id, SUM(salary),AVG(salary)
FROM     employees
GROUP BY department_id, job_id ;

1

#错误的!
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) avg_sal
FROM employees
GROUP BY department_id
ORDER BY avg_sal ASC;

1

3. GROUP BY中使用WITH ROLLUP

使用WITH ROLLUP关键字之后,在所有查询出的分组记录之后增加一条记录,该记录计算查询出的所有记录的总和,即统计记录数量

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

1

注意:
当使用ROLLUP时,不能同时使用ORDER BY子句进行结果排序,即ROLLUP和ORDER BY是互相排斥的。

五、HAVING

1. 基本使用

过滤分组:HAVING子句

  1. 行已经被分组。
  2. 使用了聚合函数。
  3. 满足HAVING 子句中条件的分组将被显示。
  4. HAVING 不能单独使用,必须要跟 GROUP BY 一起使用。
    1
SELECT   department_id, MAX(salary) max_sal
FROM     employees
GROUP BY department_id
HAVING max_sal > 10000;

1

2. HAVING 与 WHERE 的区别

where 和 having 都能使用 但是 where不能作为分组的条件

非法使用聚合函数 : 不能在 WHERE 子句中使用聚合函数。
在这里插入图片描述
区别一:

  • WHERE 可以直接使用表中的字段作为筛选条件,但不能使用分组中的计算函数作为筛选条件;
  • HAVING 必须要与 GROUP BY 配合使用,可以把分组计算的函数和分组字段作为筛选条件。

区别二:

  • 如果需要通过连接从关联表中获取需要的数据,WHERE 是先筛选后连接,而 HAVING 是先连接后筛选
优点缺点
WHERE先筛选数据再关联,执行效率高不能使用分组中的计算函数进行筛选
HAVING可以使用分组中的计算函数在最后的结果集中进行筛选,执行效率较低

结论:
当过滤条件中有聚合函数时,则此过滤条件必须声明在HAVING中。
当过滤条件中没有聚合函数时,则此过滤条件声明在WHERE中或HAVING中都可以。但是,建议大家声明在WHERE中。

SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10,20,30,40)
GROUP BY department_id
HAVING MAX(salary) > 10000;

1

/*
  WHERE 与 HAVING 的对比
1. 从适用范围上来讲,HAVING的适用范围更广。 
2. 如果过滤条件中没有聚合函数:这种情况下,WHERE的执行效率要高于HAVING
*/

六、SELECT的执行过程

1. 查询结构

#方式1:
SELECT ...,....,...
FROM ...,...,....
WHERE 多表的连接条件
AND 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...

#方式2:
SELECT ...,....,...
FROM ... JOIN ... 
ON 多表的连接条件
JOIN ...
ON ...
WHERE 不包含组函数的过滤条件
AND/OR 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...

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

2. SELECT执行顺序

  1. 关键字的顺序是不能颠倒的:
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT...

2. SELECT 语句的执行顺序(在 MySQL 和 Oracle 中,SELECT 执行顺序基本相同):

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 的字段 -> DISTINCT -> ORDER BY -> LIMIT

举例:

SELECT DISTINCT player_id, player_name, count(*) as num # 顺序 5
FROM player JOIN team ON player.team_id = team.team_id # 顺序 1
WHERE height > 1.80 # 顺序 2
GROUP BY player.team_id # 顺序 3
HAVING num > 2 # 顺序 4
ORDER BY num DESC # 顺序 6
LIMIT 2 # 顺序 7

在 SELECT 语句执行这些步骤的时候,每个步骤都会产生一个虚拟表,然后将这个虚拟表传入下一个步骤中作为输入。
需要注意的是,这些步骤隐含在 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 ...,....

*/
#SQL语句的执行过程:
#FROM ...,...-> ON -> (LEFT/RIGNT  JOIN) -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> 
# ORDER BY -> LIMIT

综合练习

#1.where子句可否使用组函数进行过滤?
--  不能

#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的员工人数( 每个job有多少员工人数
SELECT job_id,COUNT(job_id)
FROM employees
GROUP BY job_id WITH ROLLUP;

SELECT job_id, COUNT(*)
FROM employees
GROUP BY job_id;

# 5.查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT MAX(salary) - MIN(salary)
FROM employees;


# 6*.查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
SELECT manager_id , MIN(salary) AS min_sal
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING min_sal > 6000


# 7*.查询所有部门的名字,location_id,员工数量和平均工资,并按平均工资降序
SELECT  d.department_name,location_id,COUNT(employee_id),AVG(salary) AS avg_sal
FROM employees e 
RIGHT JOIN departments d 
ON e.department_id = d.department_id
GROUP BY d.department_name,location_id
ORDER BY avg_sal DESC;

# 8.查询部门名字,所有工种和最低工资
SELECT d.department_name,e.job_id,MIN(e.salary)
FROM employees e LEFT JOIN departments d 
ON e.department_id = d.department_id
GROUP BY d.department_name,e.job_id
文章来源:https://blog.csdn.net/GavinGroves/article/details/135480733
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。