2017-07-29 35 views
2

我們正在嘗試計算滾動平均值並試圖轉換大量SO解決方案來解決問題。至此,我們仍然沒有成功。在SQL Server中計算遞歸滾動平均值

我們已經試過

下面是一些我們已經考慮了SO答案。

我們最新的嘗試是修改的解決方案之一(#4)這裏找到。 https://www.red-gate.com/simple-talk/sql/t-sql-programming/calculating-values-within-a-rolling-window-in-transact-sql/

這裏是SQL小提琴一個例子:http://sqlfiddle.com/#!6/4570a/17

在撥弄,我們仍然試圖讓SUM工作權,但最終我們正在試圖讓平均。

最終目標

使用的小提琴例子,我們需要找到Value1和ComparisonValue1之間的差異,目前作爲DIFF1。當一行沒有Value1可用時,我們需要通過取最後兩個Diff1值的平均值來估計它,然後將其添加到該行的ComparisonValue1。

有了正確的查詢,結果是這樣的:

GroupID Number ComparisonValue1 Diff1 Value1 
5  10  54.78    2.41 57.19 
5  11  55.91    2.62 58.53 
5  12  55.93    2.78 58.71 
5  13  56.54    2.7 59.24 
5  14  56.14    2.74 58.88 
5  15  55.57    2.72 58.29 
5  16  55.26    2.73 57.99 

問題:是可以計算這個平均值時,它可能因素納入平均值以下行的?

更新

  • 增加了一個着眼於小提琴架構來簡化最終的查詢。
  • 更新了查詢以包含Diff1的新滾動平均值(列Diff1Last2Avg)。這個滾動平均值很好,直到我們遇到Value1列中的空值。這是我們需要插入估算的地方。
  • 已更新query以包含在沒有Value1(列Value1Estimate)時應使用的估計值。如果我們可以在Value1列中使用估計來代替NULL,這是非常好的工作。由於Diff1列反映了Value1(或其估計值)與ComparisonValue1之間的差異,因此Estimated將填充Diff1中的所有NULL值。這反過來將繼續允許計算未來行的估計值。在這一點上它變得令人困惑,但仍然在嘲笑它。有任何想法嗎?
+0

如果可能減少記錄的數量和添加問題的預期結果以表格的形式。好問題 –

+0

什麼版本的SQL? – Xedni

+0

@Xedni SQL Server 2008中 –

回答

0

信貸的想法去這樣的回答:https://stackoverflow.com/a/35152131/6305294從@JesúsLópez

我已經包含在代碼中的註釋來解釋它。

UPDATE

  • 我已經改正了基於註釋的查詢。
  • 我已經換在被減數和減數號獲得差爲正數。
  • 刪除Diff2Ago列。查詢

結果現在正是你的樣品輸出相匹配。

;WITH cte AS 
(
    -- This is similar to your ItemWithComparison view 
    SELECT i.Number, i.Value1, i2.Value1 AS ComparisonValue1, 
     -- Calculated Differences; NULL will be returned when i.Value1 is NULL 
     CONVERT(DECIMAL(10, 3), i.Value1 - i2.Value1) AS Diff 
    FROM Item AS i 
      LEFT JOIN [Group] AS G ON g.ID = i.GroupID 
      LEFT JOIN Item AS i2 ON i2.GroupID = g.ComparisonGroupID AND i2.Number = i.Number 
    WHERE NOT i2.Id IS NULL 
), 
cte2 AS(
    /* 
    Start with the first number 

    Note if you do not have at least 2 consecutive numbers (in cte) with non-NULL Diff value and therefore Diff1Ago or Diff2Ago are NULL then everything else will not work; 
    You may need to add additional logic to handle these cases */ 
    SELECT TOP 1 -- start with the 1st number (see ORDER BY) 
      a.Number, a.Value1, a.ComparisonValue1, a.Diff, b.Diff AS Diff1Ago 
    FROM cte AS a 
      -- "1 number ago" 
      LEFT JOIN cte AS b ON a.Number - 1 = b.Number 
    WHERE NOT a.Value1 IS NULL 
    ORDER BY a.Number 
    UNION ALL 
    SELECT b.Number, b.Value1, b.ComparisonValue1, 
      (CASE 
       WHEN NOT b.Value1 IS NULL THEN b.Diff 
       ELSE CONVERT(DECIMAL(10, 3), (a.Diff + a.Diff1Ago)/2.0) 
      END) AS Diff, 
     a.Diff AS Diff1Ago 
    FROM cte2 AS a 
     INNER JOIN cte AS b ON a.Number + 1 = b.Number 
) 
SELECT *, (CASE WHEN Value1 IS NULL THEN ComparisonValue1 + Diff ELSE Value1 END) AS NewValue1 
FROM cte2 OPTION(MAXRECURSION 0); 

限制: 這個解決方案工作得很好,只有當你需要考慮少數前述值中的。

+0

哇,非常接近。更新了一些小問題,但它現在在[fiddle](http://sqlfiddle.com/#!6/4570a/41)中運行。雖然,結果與問題中的樣本結果不符。第一個Value1空值的估計值應該是59.24。當我移動查詢時,我是否遇到了一些問題?我會仔細檢查。 –

+0

此外,刪除了ABS函數,因爲負值對於我們的應用程序非常重要。 –

+0

我相信遞歸cte2查詢中的CASE ELSE行需要'ELSE CONVERT(DECIMAL(10,3),(a.Diff + a.Diff1Ago)/ 2.0)'。 –