2013-03-01 48 views
1

我试图计算出200列指数使用与MySQL的SQL查询移动平均线(EMA)。每行都取决于前一行的值。其计算公式为:UPDATE查询依赖于以前的记录值

EMA = ((price - EMA(previous_average)) * (2/(200 + 1))) + EMA(previous_average) 

我的表initallly看起来像

id  price  average 
--------------------------- 
1  29.05  29.05000000 
2  29.04  0.00000000 
3  29.06  0.00000000 
4  29.05  0.00000000 

(手动设置的第一行的“平均”到“价格”,所以下面的查询的初始值)

运行此查询

UPDATE 
    quotes 
INNER JOIN 
    quotes AS quotes_previous ON quotes_previous.id = table.id - 1 
SET 
    table.average = ((quotes.price - quotes_previous.average) * (2/(200 + 1)) + quotes_previous.average) 
where 
    quotes.id > 1 

我的表,则看起来像

id  price  average 
--------------------------- 
1  29.05  29.05000000 
2  29.04  29.04990050 
3  29.06  1.13937059 
3  29.05  1.13927205 

正如你所看到的,平均为所有,但前两排显然是不正确。

我相信问题是,查询需要通过ID更新才能行。但是,当我添加“ORDER BY ID”查询,我得到“错误1221(HY000):不正确的使用UPDATE和ORDER BY”。我相信我不能在UPDATE查询中使用ORDER BY和JOIN。

所以,我怎样才能运行更新查询依赖于上一行的价值?

+0

你的意思是前面的行*更新*值或更新前的值? – 2013-03-01 19:11:48

+0

如果你想使用前一行的更新值,答案是“不,你不能这样做。”更新作为单个事务执行。除非所有值已经进入表格,否则任何给定值都不会进入表格。您需要使用游标执行此操作 - 或者查找另一种表达算术的方法。 – 2013-03-01 19:13:30

+0

@戈登这就是我所害怕的。好的,有时间写一个存储过程......除非有人有一个更简单的解决方案? – 2013-03-01 19:27:41

回答

1

试试这个

UPDATE quotes q INNER JOIN 
(SELECT id, 
     price, 
     ((price - @prev) * (2/(200 + 1))) + @prev average, 
     @prev = ((price - @prev) * (2/(200 + 1))) + @prev 
    FROM quotes, (SELECT @prev := (SELECT price FROM quotes ORDER BY id LIMIT 1) i) n 
ORDER BY id) t ON q.id=t.id 
    SET q.average = t.average 

输出

+------+-------+-------------+ 
| id | price | average  | 
+------+-------+-------------+ 
| 1 | 29.05 | 29.05000000 | 
| 2 | 29.04 | 29.04990050 | 
| 3 | 29.06 | 29.05009950 | 
| 4 | 29.05 | 29.05000000 | 
+------+-------+-------------+ 

这意味着是安全的重新运行,因为它需要首先从平均行的价格与列ID最低。

+0

@ChadJohnson有帮助吗? – peterm 2013-03-04 14:10:00

+0

该死的。我看到这太迟了。我结束了使用存储过程。不过谢谢你。 – 2013-03-04 17:14:53

+0

不客气。祝你好运。 – peterm 2013-03-04 18:45:00