SQL聚合函数与分组查询详解

聚合函数是对一组数据进行汇总,输入是一组数据的集合,输出是单个数据值。

1、聚合函数介绍

聚合函数不能嵌套调用,例如不能出现 AVG(SUM(字段名称))等形式。

1.1 AVG和SUM函数

可以对数值型数据 使用AVG(平均) 和 SUM (求和)函数。SUM在使用时也会自动屏蔽NULL。

sql 复制代码
SELECT AVG(salary),SUM(salary),AVG(salary)*107
FROM employees;

1.2 MIN和MAX函数

可以对任意数据类型的数据使用 MIN (最小)和 MAX(最大) 函数。

sql 复制代码
# 数值类型
SELECT MAX(salary),MIN(salary)
FROM employees;# 24000 2100
# 字符串
SELECT MAX(hire_date),MIN(hire_date)
FROM employees; # 2000-04-21  1987-06-17

1.3 COUNT函数

作用:计算指定字段在查询结果中出现的个数。

  • COUNT(*)返回表中记录总数,适用于任意数据类型。
sql 复制代码
# 查询表中多少条记录
SELECT COUNT(employee_id),COUNT(salary),COUNT(1)
FROM employees;# 107 107 107

SELECT COUNT(*)
FROM employees
WHERE department_id = 50; # 45
  • COUNT(expr) 返回expr不为空的记录总数。(commission_pct 存在值为NULL的结果)
sql 复制代码
SELECT COUNT(commission_pct)
FROM employees; # 35
  • 公式:AVG = SUM / COUNT 一直适用,无论是否含有 NULL。
sql 复制代码
SELECT AVG(commission_pct),SUM(commission_pct)/COUNT(commission_pct),SUM(commission_pct)/107
FROM employees; # 0.222857 0.222857  0.072897

1.4 COUNT 的SQL 优化方案

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

  • 如果使用 MyISAM 引擎,三者的效率相同,都是O(1)
  • 如果使用 InnoDB 引擎,三者的执行效率:COUNT(*)= COUNT(1)> COUNT(具体字段),复杂度是O(n)直接读取行数

2、GROUP BY

2.1 基本用法

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

若要求出员工表中各个部门 的平均工资,则要使用 GROUP BY 子句将表中数据分为若干组。

sql 复制代码
SELECT department_id,AVG(salary),SUM(salary)
FROM employees
GROUP BY department_id;

代码模板:

sql 复制代码
SELECT column, group_function(column)
FROM table
[WHERE	condition] # where 如果有 则一定紧跟from之后
[GROUP BY group_by_expression]
[ORDER BY column];

2.2 多个列分组

进一步细分,同一个组内不同的工种又可以分为一个组。实现部门之间的大组以及部门内的小组。

sql 复制代码
SELECT department_id dept_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id,job_id
ORDER BY department_id;
# 两个表达等价 与排序字段的先后顺序无关
SELECT department_id dept_id,job_id,AVG(salary)
FROM employees
GROUP BY job_id,department_id
ORDER BY department_id;
  • 包含在 GROUP BY 子句中的列不必包含在SELECT 列表中(可以为了更直观表示在select字段加入额外的查询字段)
  • 在SELECT列表中所有未包含在组函数中的列都应该包含在 GROUP BY子句中!!!(以下示例是错误的)
sql 复制代码
# 错误写法 job_id不在分组语句中
SELECT department_id,job_id,AVG(salary)
FROM employees
GROUP BY department_id;

2.3 WITH ROLLUP 的使用

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

sql 复制代码
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id WITH ROLLUP;

3、HAVING

3.1 基本使用

用于过滤数据:

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

sql 复制代码
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary)>10000; # 声明在GROUP BY的后面
  • 非法使用聚合函数 : 不能在 WHERE 子句中使用聚合函数 。
sql 复制代码
# 错误示例
SELECT department_id,AVG(salary)
FROM employees
WHERE AVG(salary) > 8000
GROUP BY department_id;

要求:过滤分组

  • 行已经被分组
  • 使用了聚合函数
  • 满足 HAVING 子句的分组被查找出来
  • HAVING 不能单独使用,要与 GROUP BY 一起使用

3.2 WHERE 和 HAVING 的对比

需求:查询部门id为10,20,30,40中最高工资比10000高的部门信息

sql 复制代码
# 方式一(推荐)
SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10,20,30,40)
GROUP BY department_id
HAVING MAX(salary)>10000;
# 方式二
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary)>10000 AND department_id IN (10,20,30,40);

对于上述两种方式我们发现过滤部门编号的语句在 WHERE 和 HAVING 中均可,那么我们该如何选择呢?下面是该问题的答案:

  • 当过滤条件中有聚合函数时,此过滤条件必须声明在 HAVING 中;
  • 当过滤条件中没有聚合函数时,此过滤条件在哪个里面都可以,建议声明在 WHERE 中;

因此可以得到:HAVING 的应用范围更大;WHERE 只能解决没有聚合函数的过滤条件,但是WHERE 的效率更高。

优点 缺点
WHERE 先筛选数据再关联,执行效率高 不能使用分组中的计算函数进行筛选
HAVING 可以使用分组中的计算函数 在最后的结果集中进行筛选,执行效率较低

4、SELECT 执行过程

4.1 完整的查询结构

sql 复制代码
#方式1:SQL92
SELECT ...,....,...(存在聚合函数)
FROM ...,...,....
WHERE 多表的连接条件 AND 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...

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

4.2 执行顺序

(1)关键字的编写顺序

sql 复制代码
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT...

(2)SELECT 语句执行顺序

sql 复制代码
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 的字段 -> DISTINCT -> ORDER BY -> LIMIT

在 SELECT 语句执行这些步骤的时候,每个步骤都会产生一个虚拟表,然后将这个虚拟表传入下一个步骤中作为输入。

相关推荐
翔云1234563 小时前
Gaea(小米MySQL Proxy)整体架构
运维·数据库·mysql
jaysee-sjc3 小时前
【苍穹外卖】Day10:定时任务与 WebSocket 实时提醒实战
java·开发语言·javascript·数据库·vue.js·websocket·网络协议
牧瀬クリスだ3 小时前
Redis五大数据类型全解析:从入门到实战
java·数据库·redis·后端·缓存
瑞克-桑切斯3 小时前
PostgreSQL 14.4 源码部署 & 运维手册(CentOS7)
数据库·学习·postgresql
上海红同电子3 小时前
红同电子线束工厂100问|绝缘护套采购,材质PVC、TPE、PP该如何选型?
数据库·经验分享·职场和发展·产品运营·制造·材质
泡海椒4 小时前
JQuick-SQL “数据源 SPI”辨析:应用适配器与 Function SPI 的正确边界
数据库·驱动开发·sql
无毁的湖光-Al4 小时前
高可用之路-观测篇-那些年遇到过的指标幻觉
linux·数据库·tcp
段一凡-华北理工大学4 小时前
高炉能源系统智能化:热风炉、煤气与极致能效~系列文章02:走进热风炉:蓄热、换炉、送风的工艺机理
大数据·数据库·能源·高炉能源管控·热风炉·热风炉工作原理
紧跟先前的步伐4 小时前
Go AI Agent 实战 18|Tool Calling 的基本原理与完整执行流程
前端·数据库·人工智能·ai·golang·1024程序员节
EnCi Zheng4 小时前
AI Agent工具误调用怎么解决-从参数校验到高危二次确认的四层工程防线
大数据·数据库·人工智能