计算移动平均MySQL?

问题描述:

美好的一天,计算移动平均MySQL?

我正在使用以下代码来计算9天移动平均线。

SELECT SUM(close) 
FROM tbl 
WHERE date <= '2002-07-05' 
AND name_id = 2 
ORDER BY date DESC 
LIMIT 9 

但它不起作用,因为它在限制被调用之前首先计算所有返回的字段。换句话说,它会计算所有关闭之前或等于该日期,而不仅仅是最后9.所以我需要从返回的选择计算SUM,而不是直接计算它。

IE。从SELECT中选择SUM ...

现在我该如何去做这件事,它是非常昂贵的还是有更好的方法?

+0

请问这个平均“搬家”? – Strawberry 2016-03-23 20:25:12

+0

这只是一个静态平均值计算。运动的部分是每天计算。 – surfer190 2016-03-24 06:10:41

使用类似

SELECT 
    sum(close) as sum, 
    avg(close) as average 
FROM (
    SELECT 
     (close) 
    FROM 
     tbl 
    WHERE 
     date <= '2002-07-05' 
     AND name_id = 2 
    ORDER BY 
     date DESC 
    LIMIT 9) temp 

内查询在desc为了返回所有过滤行,然后你avgsum了这些行返回。

之所以被你给不工作的query是由于事实sum计算第一和LIMIT子句已经计算出sum后应用,给你所有存在的行的sum

+5

。 。这返回一个值。移动平均数是指“n”个记录的每个日期的单独值。 – 2013-04-20 14:50:07

+0

是的,我认为OP想要在特定的一天移动avg,'2002-07-05' – Akash 2013-04-20 14:51:56

+0

这个解决方案如果提供了一个特定的name_id,是否有办法获得表中每个name_id的移动平均值? 这意味着输出将是每个name_id – user6890 2015-09-19 10:43:13

如果你想为每个日期的均线,那就试试这个:

SELECT date, SUM(close), 
     (select avg(close) from tbl t2 where t2.name_id = t.name_id and datediff(t2.date, t.date) <= 9 
     ) as mvgAvg 
FROM tbl t 
WHERE date <= '2002-07-05' and 
     name_id = 2 
GROUP BY date 
ORDER BY date DESC 

它使用相关子查询来计算9个值的平均值。

+0

更好。我在日常触发器上使用这个功能,所以我只需要一个特定日期的MA,因为我只是为了速度而将数据库中的9日均线保存起来。但有了这个,我可以让用户为移动平均线设定他们自己的时间段,下行速度就是速度。谢谢。 – surfer190 2014-08-23 07:40:25

+3

@ surfer100奇怪的是,这不是被接受的答案 – Strawberry 2016-03-24 07:47:05

+0

颠覆这个古老的线程,因为我正在寻找使用纪元时间戳相同的答案。这里的问题是这不包括周末。 – fractal5 2017-12-13 17:49:39

这个查询速度快:

select date, name_id, 
case @i when name_id then @i:=name_id else (@i:=name_id) 
and (@n:=0) 
and (@a0:=0) and (@a1:=0) and (@a2:=0) and (@a3:=0) and (@a4:=0) and (@a5:=0) and (@a6:=0) and (@a7:=0) and (@a8:=0) 
end as a, 
case @n when 9 then @n:=9 else @n:[email protected]+1 end as n, 
@a0:[email protected],@a1:[email protected],@a2:[email protected],@a3:[email protected],@a4:[email protected],@a5:[email protected],@a6:[email protected],@a7:[email protected],@a8:=close, 
(@[email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected])/@n as av 
from tbl, 
(select @i:=0, @n:=0, 
     @a0:=0, @a1:=0, @a2:=0, @a3:=0, @a4:=0, @a5:=0, @a6:=0, @a7:=0, @a8:=0) a 
where name_id=2 
order by name_id, date 

如果您需要超过50个或100个值的平均值,这是繁琐写,但是 值得努力。速度接近有序选择。

的另一种技术是做一个表:

CREATE TABLE `tinyint_asc` (
`value` tinyint(3) unsigned NOT NULL default '0', 
PRIMARY KEY (value) 
) ; 
​ 
INSERT INTO `tinyint_asc` VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),(40),(41),(42),(43),(44),(45),(46),(47),(48),(49),(50),(51),(52),(53),(54),(55),(56),(57),(58),(59),(60),(61),(62),(63),(64),(65),(66),(67),(68),(69),(70),(71),(72),(73),(74),(75),(76),(77),(78),(79),(80),(81),(82),(83),(84),(85),(86),(87),(88),(89),(90),(91),(92),(93),(94),(95),(96),(97),(98),(99),(100),(101),(102),(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114),(115),(116),(117),(118),(119),(120),(121),(122),(123),(124),(125),(126),(127),(128),(129),(130),(131),(132),(133),(134),(135),(136),(137),(138),(139),(140),(141),(142),(143),(144),(145),(146),(147),(148),(149),(150),(151),(152),(153),(154),(155),(156),(157),(158),(159),(160),(161),(162),(163),(164),(165),(166),(167),(168),(169),(170),(171),(172),(173),(174),(175),(176),(177),(178),(179),(180),(181),(182),(183),(184),(185),(186),(187),(188),(189),(190),(191),(192),(193),(194),(195),(196),(197),(198),(199),(200),(201),(202),(203),(204),(205),(206),(207),(208),(209),(210),(211),(212),(213),(214),(215),(216),(217),(218),(219),(220),(221),(222),(223),(224),(225),(226),(227),(228),(229),(230),(231),(232),(233),(234),(235),(236),(237),(238),(239),(240),(241),(242),(243),(244),(245),(246),(247),(248),(249),(250),(251),(252),(253),(254),(255); 

后,您可以使用它像:

select date_add(tbl.date, interval tinyint_asc.value day) as mydate, count(*), sum(myvalue) 
from tbl inner join tinyint_asc.value <= 30 -- for a 30 day moving average 
where date(date_add(o.created_at, interval tinyint_asc.value day)) between '2016-01-01' and current_date() 
group by mydate