-1

あなたの助けが必要です。

データベース: SQL サーバー 2008R2

過去 4 週間の値の平均を 1 年と 1 週間計算したいと考えています。

私はそのようなテーブルにデータを持っています:

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 年のデータを借りました。

注: 年が可変週数の場合、それほど単純ではありません。より良い回答を得るには、週の計算方法に関する非常に具体的な指示を提供する必要があります。これにより、1 年の各週の実際の開始日を決定できるようになります。

最終的に、データを年単位や週単位に分割して保存することは、最適ではない可能性があります。収集されたデータの各週の週の開始日を単純に保存する方が良いと思います。

于 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

まず、日付情報を複数のフィールドに分割しないでください。つまり、それらを再結合する必要があるため、クエリが遅くなり、datetime 変数として保存することをお勧めします。

第二に、答えは

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 に答える