2017-07-29 160 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)'。 –