这看起来像是偷偷摸摸的窗口函数聚合的工作!
DECLARE @TABLE TABLE (SaleID INT IDENTITY, Cost DECIMAL(12,4), SaleDateTime DATETIME)
INSERT INTO @TABLE (SaleDateTime, Cost) VALUES
('2022-Jan-01', 1 ),
('2022-Feb-01', 5 ),
('2022-Mar-01', 8 ),
('2022-Apr-01', 12),
('2022-May-01', 15),
('2022-Jun-01', 20)
SELECT DISTINCT DATEPART(YEAR,SaleDateTime) AS Year, DATEPART(MONTH,SaleDateTime) AS MonthNumber, DATENAME(MONTH,SaleDateTime) AS Month,
AVG(Cost) OVER (ORDER BY (SELECT 1)) AS AllTimeAverage,
AVG(Cost) OVER (PARTITION BY DATEPART(YEAR,SaleDateTime), DATEPART(MONTH, SaleDateTime) ORDER BY SaleDateTime) AS MonthlyAverage,
AVG(Cost) OVER (PARTITION BY DATEPART(YEAR,SaleDateTime), DATEPART(QUARTER,SaleDateTime) ORDER BY SaleDateTime) AS QuarterlyAverage,
AVG(Cost) OVER (PARTITION BY CASE WHEN SaleDateTime BETWEEN CAST(DATEADD(MONTH,-1,DATEADD(DAY,1-DATEPART(DAY,SaleDateTime),SaleDateTime)) AS DATE)
AND CAST(DATEADD(MONTH,2,DATEADD(DAY,1-DATEPART(DAY,SaleDateTime),SaleDateTime)) AS DATE)
THEN 1 END ORDER BY SaleDateTime) AS RollingThreeMonthAverage
FROM @TABLE
ORDER BY DATEPART(YEAR,SaleDateTime), DATEPART(MONTH,SaleDateTime)
我们在这里作弊,让 case 表达式在我们的 3 个月滚动窗口中找到我们想要的行。我选择将其保留在上个月、本月和下个月的滚动窗口(从上个月的第一天到下个月的最后一天 - '2022-01-01 00:00:00' 到2 月的 '2022-04-01 00:00:00')。
对整个结果集、月份和季度进行分区很简单,但是当您将滚动的三个月转换为描述它的 case 表达式时并不会复杂多少。
Year MonthNumber Month AllTimeAverage MonthlyAverage QuarterlyAverage RollingThreeMonthAverage
--------------------------------------------------------------------------------------------------------
2022 1 January 10.166666 1.000000 1.000000 1.000000
2022 2 February 10.166666 5.000000 3.000000 3.000000
2022 3 March 10.166666 8.000000 4.666666 4.666666
2022 4 April 10.166666 12.000000 12.000000 6.500000
2022 5 May 10.166666 15.000000 13.500000 8.200000
2022 6 June 10.166666 20.000000 15.666666 10.166666