T-SQL вычисляет скользящее среднее

Я работаю с SQL Server 2008 R2, пытаясь вычислить скользящую среднюю. Для каждой записи, на мой взгляд, я хотел бы собрать значения 250 предыдущих записей, а затем вычислить среднее значение для этого выбора.

Мои столбцы просмотра выглядят следующим образом:

TransactionID | TimeStamp           | Value | MovAvg
----------------------------------------------------
            1 | 01.09.2014 10:00:12 |     5 |    
            2 | 01.09.2014 10:05:34 |     3 | 
...
          300 | 03.09.2014 09:00:23 |     4 | 

TransactionID является уникальным. Для каждого TransactionID я хотел бы рассчитать среднее значение столбца по сравнению с предыдущими 250 записями. Поэтому для TransactionID 300 собирайте все значения из предыдущих 250 строк (просмотр сортируется по убыванию TransactionID), а затем в столбце MovAvg записывается результат среднего значения этих значений. Я собираюсь собирать данные в пределах диапазона записей.

Ответы

Ответ 1

Функции окна в SQL 2008 довольно ограничены по сравнению с более поздними версиями, и если я правильно помню, вы можете только разделять, и вы не можете использовать ограничение на количество строк/диапазонов, но я думаю, что это может быть то, что вы хотите:

;WITH cte (rn, transactionid, value) AS (
    SELECT 
       rn = ROW_NUMBER() OVER (ORDER BY transactionid),
       transactionid,
       value
    FROM your_table
)

SELECT 
    transactionid, 
    value, 
    movagv = (
        SELECT AVG(value) 
        FROM cte AS inner_ref
        -- average is calculated for 250 previous to current row inclusive
        -- I might have set the limit one row to large, maybe it should be 249
        WHERE inner_ref.rn BETWEEN outer_ref.rn-250 AND outer_ref.rn
        ) 
FROM cte AS outer_ref

Обратите внимание, что он применяет коррелированный подзапрос к каждой строке, и производительность может быть невелика.

В более поздних версиях вы могли использовать функции оконного кадра и сделали что-то вроде этого:

SELECT 
    transactionid, 
    value,
    -- avg over the 250 rows counting from the previous row
    AVG(value) OVER (ORDER BY transactionid  
                     ROWS BETWEEN 251 PRECEDING AND 1 PRECEDING),
    -- or 250 rows counting from current
    AVG(value) OVER (ORDER BY transactionid  
                     ROWS BETWEEN 250 PRECEDING AND CURRENT ROW)
FROM your_table

Ответ 2

Используйте Common Table Expression (CTE), чтобы включить rownum для каждой транзакции, затем присоедините CTE к себе по номеру строки, чтобы вы может получить предыдущие значения для вычисления среднего значения с помощью.

CREATE TABLE MyTable (TransactionId INT, Value INT)

;with Data as
(
  SELECT TransactionId, 
         Value, 
         ROW_NUMBER() OVER (ORDER BY TransactionId ASC) as rownum
  FROM MyTable
)
SELECT d.TransactionId , Avg(h.Value) as MovingAverage
FROM Data d
JOIN Data h on h.rownum between d.rownum-250 and d.rownum-1
GROUP BY d.TransactionId