我正在尝试从以下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
任何帮助将不胜感激。
答案 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
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;