SQL实现按月份累计求和:替代低效Union查询方案
问题描述
我有一张包含pieces(数量)和Date(日期)两列的数据表,示例数据如下:
pieces Date 100 2022-01-01 200 2022-02-01 300 2022-03-01
以此类推。我需要实现按月份累计求和,期望得到如下结果:
january - 100 pieces february - 300 pieces march - 600 pieces
目前我尝试用多个SELECT语句分别计算截至各月末的总和,再通过UNION合并结果,但这种方式效率很低,代码如下:
select sum(pieces) , 'january' as month from table where date <= '2022-01-31' union select sum(pieces) , 'february' as month from table where date <= '2022-02-28' union select sum(pieces) , 'march' as month from table where date <= '2022-03-31'
高效解决方案
可以利用窗口函数实现一次扫描表完成累计求和,效率远高于多次UNION的方式,以下是适配不同数据库的实现方案:
MySQL 版本
SELECT LOWER(MONTHNAME(date)) AS month, CONCAT(SUM(pieces) OVER (ORDER BY MONTH(date)), ' pieces') AS result FROM your_table GROUP BY MONTH(date), MONTHNAME(date) ORDER BY MONTH(date);
PostgreSQL 版本
SELECT LOWER(TO_CHAR(date, 'FMMonth')) AS month, CONCAT(SUM(pieces) OVER (ORDER BY EXTRACT(MONTH FROM date)), ' pieces') AS result FROM your_table GROUP BY EXTRACT(MONTH FROM date), TO_CHAR(date, 'FMMonth') ORDER BY EXTRACT(MONTH FROM date);
SQL Server 版本
SELECT LOWER(DATENAME(MONTH, date)) AS month, CONCAT(SUM(pieces) OVER (ORDER BY MONTH(date)), ' pieces') AS result FROM your_table GROUP BY MONTH(date), DATENAME(MONTH, date) ORDER BY MONTH(date);
核心逻辑说明
- 用数据库内置函数提取月份的英文名称,并转为小写以匹配期望格式
SUM(pieces) OVER (ORDER BY 月份序号)是累计求和的核心:窗口函数会按月份顺序,自动累加当前及之前所有月份的pieces总和- 通过
GROUP BY确保每个月份只返回一条记录,最后按月份序号排序保证结果顺序正确
优势
- 仅需扫描数据表一次,避免了多次
SELECT+UNION的重复扫描,数据量越大效率提升越明显 - 无需手动指定每个月末日期,自动适配不同月份的天数(如2月的28/29日)
内容的提问来源于stack exchange,提问作者Matheus Esteves
相关产品推荐
相关产品推荐

