【问题标题】:T-SQL calculate moving averageT-SQL计算移动平均线
【发布时间】:2014-12-24 10:46:48
【问题描述】:

我正在使用 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 中写入这些值的平均值。我希望收集一系列记录中的数据。

【问题讨论】:

  • 查看PARTITION BYROW_NUMBER
  • 谢谢。你有什么建议吗?
  • @RunW 相同的事务 id 以不同的值重复,除了事务 id 是否有时间戳列或身份列?
  • @RunW,你能提供示例数据吗?如果事务 id 是唯一的,你将如何拥有相同 id 的 250 条以前的记录?
  • @RunW 如果您编辑问题并包含示例数据,您将能够对其进行更多格式化。此外,并不是每个人都会阅读 cmets,因此在阅读问题并决定是否要回答时,它会对其他人有所帮助。

标签: sql tsql sql-server-2008-r2 window-functions moving-average


【解决方案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

【讨论】:

  • 非常感谢。这当然是这样做的方法,但正如你所说,性能相当糟糕。感谢您的帮助。
  • 在 SQL 2008 中是否有更有效的方法来执行此操作,它不会在每一行上运行相关子查询?我一直在绞尽脑汁想想出一个可以缩短执行时间的解决方案,但我一直做不到。
  • @mitchimus 可能有,但我不知道有什么 - 我没有考虑太多,因为更高版本的服务器版本有更好的选择。
【解决方案2】:

使用Common Table Expression (CTE) 包含每个事务的行号,然后在行号上将 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 

【讨论】:

    猜你喜欢
    • 2014-11-18
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多