计算过去4周滚动的平均值

时间:2012-12-20 04:42:41

标签: sql sql-server sql-server-2008 tsql

我需要你的帮助。

数据库:SQL SERVER 2008R2

我想计算一周和一周的最后4周的平均价值。

我的数据表是这样的:

YEAR    WEEKS   VALUE 
2012    1   3000
2012    2   5000
2012    3   6000
2012    4   7000
2012    5   8000
2012    6   9000
2012    7   1000
2012    8   6000
2012    9   9000
2012    10  4000

我想要那个:

YEAR       WEEKS      VALUE
2012        1           ( Average value for week 49, 50, 51, 52 for the year 2011)
2012        2         ( Average value for week 50, 51, 52 for the year 2011 and week 1                    for the year 2012)
2012        3           ( Average value for week 51, 52 for the year 2011 and week 1, 2 for the year 2012)
2012        4           ( Average value for week 52 for the year 2011 and week 1, 2, 3 for the year 2012)
2012        5          5250 -> (  Average value for  week 1, 2, 3 , 4 for the year 2012)
2012        6          6500 -> (  Average value for  week 2, 3 , 4, 5 for the year 2012)

3 个答案:

答案 0 :(得分:3)

如果岁月总是有52周,那么这里有一个简单的方法:

SELECT
   DataYear = N.Serial / 52,
   DataWeek = N.Serial % 52 + 1,
   Avg(T.Value)
FROM
   dbo.DataTable T
   CROSS JOIN (VALUES (0), (1), (2), (3)) W (Offset)
   CROSS APPLY (SELECT T.Year * 52 + Week + W.Offset) N (Serial)
GROUP BY
   N.Serial / 52,
   N.Serial % 52 + 1
HAVING
   Count(*) = 4 -- if you don't want smaller sets
ORDER BY
   DataYear,
   DataWeek;

See this in action in a SQLFiddle。我不得不在2011年底添加假数据以匹配您的示例输出。我从Alexander Fedorenko那里借用了2011年的数据,以便进行比较。

注意:如果年份的周数可变,则不会那么简单。为了获得更好的答案,您需要提供有关如何计算周数的详细说明,足够的详细信息,以便我们确定一年中每周的实际开始日期。

最终,将数据分成数年和数周存储可能不是最佳的。我认为最好只存储每周收集数据的周开始日期。

答案 1 :(得分:1)

使用递归CTE

;WITH cte AS
 (
  SELECT [YEAR], WEEKS, VALUE,
         ROW_NUMBER() OVER (ORDER BY [YEAR], WEEKS) AS id
  FROM your_table
  --WHERE your condition range of dates
  ), cte2 AS
 (
  SELECT id,
         CASE WHEN id = 5 THEN [YEAR] END AS [YEAR],
         CASE WHEN id = 5 THEN WEEKS END AS WEEKS,
         CASE WHEN id != 5 THEN VALUE END AS VALUE, 1 AS [Level]
  FROM cte
  UNION ALL
  SELECT c.id,
         CASE WHEN ct.id - ct.[Level] = 4 THEN c.[YEAR] END,
         CASE WHEN ct.id - ct.[Level] = 4 THEN c.WEEKS END,
         CASE WHEN ct.id - ct.[Level] != 4 THEN c.VALUE END, ct.[Level] + 1
  FROM cte c JOIN cte2 ct ON c.id = ct.id + 1
  WHERE ct.id < 5 + [Level]
  )
  SELECT MAX([YEAR]) AS [YEAR], MAX(WEEKS) AS WEEKS, AVG(VALUE) AS avgVALUE
  FROM cte2
  WHERE id = CASE WHEN [Level] = 1 AND id > 5 THEN NULL ELSE id END 
  GROUP BY [level]
  HAVING MAX([YEAR]) IS NOT NULL

SQLFiddle上的演示

答案 2 :(得分:0)

首先,不要在多个字段之间分割日期信息,这意味着必须重新组合以减慢查询速度,最好将其存储为日期时间变量。

其次,答案是

WITH  Data
AS
(
    SELECT   CAST(CAST(Year AS VARCHAR) + CAST(Weeks AS VARCHAR) AS INTEGER) AS WeekNum
            ,Year
            ,Weeks
            ,Value
            ,1 AS Depth
    FROM    WeekData
    UNION ALL
    SELECT   d.WeekNum
            ,d.Year
            ,d.Weeks
            ,wd.Value
            ,d.Depth + 1
    FROM    WeekData wd
            INNER JOIN
            Data d  ON d.WeekNum=CAST(CAST(wd.Year AS VARCHAR) + CAST(wd.Weeks AS VARCHAR) AS INTEGER)-d.Depth
                    AND
                    d.Depth<4
)
SELECT   Year
        ,Weeks
        ,AVG(Value) AS AverageValue
FROM    Data
GROUP BY Year
        ,Weeks