使用范围在SQL Server 2012中滚动平均值

时间:2013-03-23 07:54:40

标签: sql tsql sql-server-2012 analytic-functions

我正在尝试计算按地区和月份分组的3个月滚动平均值,如

Region  Month                 Avg(var_a)    Avg(var_b)
Northland   Dec-Jan-Feb       7.1           5.9
Southland   Dec-Jan-Feb       7.2               6.1
Northland   Nov-Dec-Jan       7.4           6.1
Southland   Nov-Dec-Jan       7.5           6.2
Northland   Oct-Nov-Dec       7.5               6.2
Southland   Oct-Nov-Dec       7.5           6.1

请注意,月份是为了说明目的而扩展的,我真的希望输出只是说一个月。

现在我可以通过按区域和月份创建CTE分组,然后加入它几次,例如

With month_rollup_cte as
    (Select region,month,sum(var_a) a_sum, sum(var_b) b_sum, count(1) cnt
From vw_score_by_region
    Group by region,month)
Select c1.region, c1.month,sum(c1.a_sum + c2.a_sum + c3.a_sum) / sum(c1.cnt + c2.cnt + c3.cnt) a_avg, sum(c1.b_sum + c2.b_sum + c3.b_sum) / sum(c1.cnt + c2.cnt + c3.cnt) b_avg
From month_rollup_cte c1
Join month_rollup_cte c2 on c1.region = c2. Region and c1.month = dateadd(mm,1,c2.month)
Join month_rollup_cte c3 on c1.region = c3. Region and c1.month = dateadd(mm,2,c3.month)
Group by c1.region, c1.month;

但这很难看,想象一下如果你不得不做6个月的滚动平均值或12个月的滚动平均值......我正在尝试使用t-sql 2012分析函数,特别是RANGE选项。我之前使用的是ROWS,但从未使用范围。

我试过的是

select region,avg(var_a) OVER (order by (year(entry_month) * 100 + month(entry_month)) range between 2 preceding and 1 following)    
from [dbo].[vw_score_by_region]
group by region

但是我收到语法错误:

  

* Msg 8120,Level 16,State 1,Line 2
  列'dbo.vw_score_by_region.month'在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。*

显然我正在做些傻事,但我不确定是什么。

1 个答案:

答案 0 :(得分:1)

首先 RANGE 仅支持 UNBOUNDED CURRENT ROW 帧分隔符,不能与 N PRECEDING一起使用< / strong>或 N跟随
从你的标题看起来,你想要获得3个月的平均值(滑动平均值),那么你最好使用 ROWS
使用 ROWS (这更有可能是您需要的)SQl Fiddle Demo


select region,
       avg(var_a) OVER (partition by region 
                        order by (entry_month) 
                        rows between 2 preceding and current row) as ThreeMonthSlidingAvg  
from [dbo].[vw_score_by_region]

注意:

No need to calcuate year+month, if entry_month is date or datetime, it is sortable already, thanks for Steve's correction.
使用RANGE:

select region,
       avg(var_a) OVER (partition by region,(year(entry_month) * 12 + month(entry_month))/3
order by (entry_month) range between unbounded preceding and current row) as ThreeMonthSlidingAvg
from [dbo].[vw_score_by_region]
注意:使用RANGE你必须控制分区宽度,因为你想要3个月的聚合,而范围不支持 N PRECEDING N FOLLOWING ,它只支持以下:

|  UNBOUNDED PRECEDING  | Starts the window at first row of the partition 
|  UNBOUNDED FOLLOWING  | Ends the window at last row of the partition 
|  CURRENT ROW          | Starts or Ends the window at current row