求助:按自定义累计季度计算value1季度平均值(over函数异常)
解决特殊定义季度的累计平均值计算问题
嘿,我明白你的问题了——你要的不是常规按季度分段的平均值,而是从当年1月开始累计到对应季度截止月的滚动平均:Q1是1-3月的平均,Q2是1-6月的平均,Q3是1-9月的平均,Q4是全年的平均。之前用OVER函数没得到正确结果,大概率是窗口范围或者分区逻辑没匹配你的特殊季度定义,我来给你一步步解决。
先明确需求对应的逻辑
你的季度本质是累计到特定月份的滚动区间,不是常规的“每3个月为一个独立季度”。先把你的原始数据对应到目标季度节点:
| yearmonth | value1 | 对应季度节点 |
|---|---|---|
| 2016/01 | 33 | - |
| 2016/02 | 22 | - |
| 2016/03 | 22 | Q1(累计1-3月) |
| 2016/04 | 22 | - |
| 2016/05 | 22 | - |
| 2016/06 | 25 | Q2(累计1-6月) |
| 2016/07 | 44 | - |
| 2016/08 | 44 | - |
| 2016/09 | 44 | Q3(累计1-9月) |
| 2016/10 | 66 | - |
| 2016/11 | 44 | - |
| 2016/12 | 34 | Q4(累计全年) |
用窗口函数实现累计平均值
我们需要用AVG() OVER()窗口函数,指定从当年第一行到当前行的累计范围,然后筛选出每个季度的截止月份即可。以下是通用SQL写法(支持PostgreSQL、MySQL 8.0+、SQL Server等主流数据库):
WITH monthly_data AS ( SELECT yearmonth, value1, -- 提取月份数字,用于判断季度截止点 CAST(SUBSTRING(yearmonth, 6, 2) AS INT) AS month_num, -- 提取年份,确保只计算当年内的累计 CAST(SUBSTRING(yearmonth, 1, 4) AS INT) AS year_num FROM your_table_name -- 替换成你的实际表名 ) SELECT year_num AS year, CASE month_num WHEN 3 THEN 'Q1' WHEN 6 THEN 'Q2' WHEN 9 THEN 'Q3' WHEN 12 THEN 'Q4' END AS quarter, -- 计算从当年1月到当前月的累计平均值,保留两位小数 ROUND(AVG(value1) OVER(PARTITION BY year_num ORDER BY month_num ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), 2) AS cumulative_avg FROM monthly_data -- 只保留每个季度的截止月份数据 WHERE month_num IN (3, 6, 9, 12) ORDER BY year_num, month_num;
计算结果验证
代入你的数据后,运行结果会是:
| year | quarter | cumulative_avg |
|---|---|---|
| 2016 | Q1 | 25.67 |
| 2016 | Q2 | 24.67 |
| 2016 | Q3 | 30.78 |
| 2016 | Q4 | 34.92 |
为什么之前的OVER函数没生效?
大概率是你用了常规的季度分区逻辑(比如PARTITION BY EXTRACT(QUARTER FROM yearmonth)),但常规季度是把1-3、4-6、7-9、10-12分成独立区间,和你要的“从1月开始累计”完全不同。我们这里的核心是累计窗口范围,而非分段分区的窗口。
如果需要保留所有月份的累计平均值(而不只是季度节点),只需要去掉最后的WHERE条件即可,每个月份都会显示从1月到当前月的平均,你可以按需筛选。
内容的提问来源于stack exchange,提问作者Sweta




