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

相关推荐
Evan10243 小时前
MySQL 8.4.7版本下载&安装详细教程(Win11环境)
mysql
2301_800050993 小时前
mysql
数据库·笔记·mysql
数据皮皮侠4 小时前
2m气温数据集(1940-2024)
大数据·数据库·人工智能·制造·微信开放平台
Psycho_MrZhang4 小时前
Redis 设计思想总结
数据库·redis·缓存
曹牧5 小时前
Java:Assert.isTrue()
java·前端·数据库
程序员葫芦娃6 小时前
【Java毕设项目】基于SSM的旅游资源网站
java·开发语言·数据库·编程·课程设计·旅游·毕设
2401_865854886 小时前
怎样挑选适合业务的数据库云服务?
数据库
lkbhua莱克瓦246 小时前
基础-函数
开发语言·数据库·笔记·sql·mysql·函数
福大大架构师每日一题7 小时前
dify 1.11.2 正式发布:向量数据库、安全增强、测试优化与多语言支持全面升级
数据库·安全