基于月份分组的SQL高效查询需求:聚合MAX/MIN/AVG值
性能最优的SQL分组查询实现方案
原始数据
| date | data_type | data_value |
|---|---|---|
| 01-01-2023 | max | 4 |
| 02-01-2023 | min | 7 |
| 03-01-2023 | avg | 54 |
| 04-01-2023 | max | 8 |
| 05-01-2023 | min | 98 |
| 06-01-2023 | avg | 23 |
| 01-02-2023 | max | 65 |
| 02-02-2023 | min | 2 |
| 03-02-2023 | avg | 45 |
| 04-02-2023 | max | 22 |
| 05-02-2023 | min | 56 |
| 06-02-2023 | avg | 65 |
| 01-03-2023 | max | 7 |
| 02-03-2023 | min | 5 |
| 03-03-2023 | avg | 23 |
| 04-03-2023 | max | 65 |
| 05-03-2023 | min | 51 |
| 06-03-2023 | avg | 33 |
需求说明
按月份分组,分别计算:
- 每个月中
data_type为'max'的data_value的最大值 - 每个月中
data_type为'min'的data_value的最小值 - 每个月中
data_type为'avg'的data_value的平均值
期望结果:
| month | max | min | avg |
|---|---|---|---|
| 1 | 8 | 7 | 38.5 |
| 2 | 65 | 2 | 55 |
| 3 | 65 | 5 | 28 |
性能最优的SQL语句
使用条件聚合实现,只需扫描一次表,是性能最优的方案:
SELECT EXTRACT(MONTH FROM TO_DATE(date, 'DD-MM-YYYY')) AS month, MAX(CASE WHEN data_type = 'max' THEN data_value END) AS max, MIN(CASE WHEN data_type = 'min' THEN data_value END) AS min, AVG(CASE WHEN data_type = 'avg' THEN data_value END) AS avg FROM your_table_name GROUP BY EXTRACT(MONTH FROM TO_DATE(date, 'DD-MM-YYYY')) ORDER BY month;
性能优势说明
- 单次扫描:该查询仅对表执行一次全表扫描(若
date字段有索引,则可利用索引快速过滤分组),避免了子查询、多表JOIN等方案带来的多次扫描开销。 - 高效聚合:条件聚合逻辑直接在GROUP BY阶段完成计算,无需额外的中间结果集处理。
- 兼容性广:该语法适用于绝大多数关系型数据库(如MySQL、PostgreSQL、Oracle等),仅需根据数据库类型微调日期转换函数(例如MySQL可用
MONTH(STR_TO_DATE(date, '%d-%m-%Y')))。
索引优化建议
若表数据量较大,可创建联合索引进一步提升性能:
-- MySQL示例 CREATE INDEX idx_date_datatype_value ON your_table_name(date, data_type, data_value);
该索引可让数据库直接通过索引完成分组和聚合计算,无需回表查询原始数据。
内容的提问来源于stack exchange,提问作者Danilo Giovannico
相关产品推荐
相关产品推荐

