SQL平均绝对偏差

时间:2019-08-06 15:33:16

标签: sql sql-server window-functions

我正在尝试从以下SQL表计算“平均绝对偏差”:

|ID  | Typical | SMA    | MAD
| 1  | 10      |        |
| 2  | 20      |        |
| 3  | 5       |  11.67 | 
| 4  | 12      |  12.33 |
| 5  | 14      |  10.33 | 
| 6  | 6       |  10.67 |
| 7  | 2       |  7.33  | 
| 8  | 17      |  8.33  |
| 9  | 5       |  8.00  |

计算MAD要求: SUM(ABS(当前行SMA-典型))在前2行和当前。然后将其除以3。因此对于ID#3,它将是:

MAD =(ABS(11.67-5)+ ABS(11.67-20)+ ABS(11.67-10))/ 3

我首先使用Dyamic SQL进行了此操作,循环并为上一行创建了LAG。这是可行的,但是当将其扩展到较高的回溯期时,效率非常低。然后,我尝试了以下我真正认为可行的方法,但没有成功:

DECLARE @sma_current numeric(20,10) 

UPDATE PY SET 
    @sma_current = [SMA(20)], 
    [MAD] = W.[MAD] 
FROM (     
    SELECT  [id],    
    ((sum(abs(@sma_current - [Typical])) OVER (ORDER BY [id] ASC ROWS 
BETWEEN 2 PRECEDING AND CURRENT ROW))/3) [MAD]    
    FROM PY ) W WHERE PY.[id] = W.[id] AND PY.[id] >= 3 

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

由于ID是连续的并且没有间隙,因此您可以使用双重自连接进行更新:

update p
set p.mad = round( 
  (abs(p.sma - p.typical) + abs(p.sma - p1.typical) + abs(p.sma - p2.typical)) / 3.0
  , 2)
from py p 
inner join py p1 on p1.id + 1 = p.id
inner join py p2 on p2.id + 2 = p.id

请参见demo

或使用lag()窗口功能:

with cte as (
  select *,
    lag(typical, 1) over (order by id) typical1,
    lag(typical, 2) over (order by id) typical2
  from py  
)
update cte
set mad = round( 
  (abs(sma - typical) + abs(sma - typical1) +  abs(sma - typical2)) / 3.0
  , 2)
from cte

请参见demo

结果:

> ID | Typical |   SMA |  MAD
> -: | ------: | ----: | ---:
>  1 |      10 |       | 
>  2 |      20 |       | 
>  3 |       5 | 11.67 | 5.56
>  4 |      12 | 12.33 | 5.11
>  5 |      14 | 10.33 | 3.56
>  6 |       6 | 10.67 | 3.11
>  7 |       2 |  7.33 | 4.44
>  8 |      17 |  8.33 | 5.78
>  9 |       5 |     8 |    6

答案 1 :(得分:0)

我猜您正在使用SQL Server。您可以使用可更新的CTE /子查询,因此可以在此处进行计算,然后进行设置:

WITH toupdate as (
      SELECT  id,    
              (sum(abs(@sma_current - [Typical])) OVER (ORDER BY [id] ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) / 3) as new_mad   
      FROM PY 
     )
UPDATE toupdate
    SET mad = new_mad;