2014-10-28 195 views
15

我正在使用SQL Server 2008 R2,嘗試計算移動平均值。對於我的觀點中的每條記錄,我想收集250條以前記錄的值,然後計算此選擇的平均值。T-SQL計算移動平均值

我的看法列如下:

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中寫入這些值的平均值的結果。我期待在一系列記錄中收集數據。

+2

看看'PARTITION BY'和'ROW_NUMBER' – Mihai 2014-10-28 21:00:08

+0

謝謝。你有什麼機會就如何做到這一點提出建議? – RunW 2014-10-28 21:04:23

+0

@RunW做同樣的事務ID重複不同的值,是否有時間戳列或標識列除了事務ID? – radar 2014-10-28 21:12:35

回答

20

在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 
+0

非常感謝。這當然是做到這一點的方法,但正如你所說,表現相當糟糕。感謝你的幫助。 – RunW 2014-10-29 06:08:31

+0

在SQL 2008中是否有更有效的方法在每行上都不運行相關的子查詢?我一直在絞盡腦汁想出一個解決方案來減少我的執行時間,但我一直在縮短。 – mitchimus 2015-04-28 02:10:56

+0

@mitchimus可能有,但我沒有意識到任何 - 我沒有多少考慮它,但因爲以後的服務器版本有更好的選擇。 – jpw 2015-04-28 11:07:19

5

使用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