-1

我需要你的帮助。

数据库:SQL SERVER 2008R2

我想计算一年零一周的最后一周的平均值。

我有这样的表格数据:

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)
4

3 回答 3

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;

在 SQLFiddle 中查看此操作。我不得不添加 2011 年底的假数据以匹配您的示例输出。我从 Alexander Fedorenko 那里借用了 2011 年的数据,以便于比较。

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

最终,将数据拆分为数年和数周存储可能不是最佳选择。我认为最好简单地存储每周收集的数据的开始日期。

于 2012-12-20T10:22:11.733 回答
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上的演示

于 2012-12-20T10:11:48.433 回答
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
于 2012-12-20T05:29:15.050 回答