Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 计算移动平均值?_Mysql_Sql_Database - Fatal编程技术网

Mysql 计算移动平均值?

Mysql 计算移动平均值?,mysql,sql,database,Mysql,Sql,Database,你好 我使用下面的代码来计算9天移动平均线 SELECT SUM(close) FROM tbl WHERE date <= '2002-07-05' AND name_id = 2 ORDER BY date DESC LIMIT 9 但它不起作用,因为它在调用限制之前首先计算所有返回的字段。换句话说,它将计算该日期之前或之前的所有收盘价,而不仅仅是最后9个收盘价 所以我需要根据返回的select计算总和,而不是直接计算 即,从选择框中选择总和 现在我该怎么做呢?这是非常昂贵还是有更好

你好

我使用下面的代码来计算9天移动平均线

SELECT SUM(close)
FROM tbl
WHERE date <= '2002-07-05'
AND name_id = 2
ORDER BY date DESC
LIMIT 9
但它不起作用,因为它在调用限制之前首先计算所有返回的字段。换句话说,它将计算该日期之前或之前的所有收盘价,而不仅仅是最后9个收盘价

所以我需要根据返回的select计算总和,而不是直接计算

即,从选择框中选择总和

现在我该怎么做呢?这是非常昂贵还是有更好的方法

使用类似

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顺序返回所有筛选的行,然后对返回的行求和


您给出的查询不起作用的原因是,首先计算总和,并且在计算总和之后应用LIMIT子句,为您提供当前所有行的总和。如果您想要每个日期的移动平均值,请尝试以下操作:

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个值的平均值。

此查询速度快:

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:=@n+1 end as n,
@a0:=@a1,@a1:=@a2,@a2:=@a3,@a3:=@a4,@a4:=@a5,@a5:=@a6,@a6:=@a7,@a7:=@a8,@a8:=close,
(@a0+@a1+@a2+@a3+@a4+@a5+@a6+@a7+@a8)/@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

从MySQL 8开始,您应该为此使用窗口函数。使用window RANGE子句,您可以在一个时间间隔内创建一个非常强大的窗口。大概是这样的:

选择 日期 关 按日期描述的平均成交订单范围间隔前9天 来自tbl
日期在哪里。这将返回一个值。移动平均值是指n条记录的每个日期的一个单独值。是的,我假设OP想要某一天的移动平均值,2002-07-05如果提供了一个特定的名称id,该解决方案有效,是否有办法获得表中每个名称id的移动平均值?因此,这意味着输出将是每个名称的移动平均值表。如果您可以删除名称id的过滤器,并将此字段添加到group by子句中,您还需要删除limit子句,并将9天的日期条件范围添加为您的开始日期和结束日期之间的日期,效果更好。我在每日触发器上使用它,所以我只需要某一天的MA,因为我在数据库中保存9天移动平均值只是为了提高速度。但有了这个,我可以让用户为移动平均线设置自己的周期,缺点是速度。谢谢。@surfer100奇怪,这不是被接受的答案,因为我正在使用历元时间戳寻找相同的答案。这里的问题是,这不包括周末。@fractal5您可以对日期设置时间戳。若要说明缺少的日期,您需要加入一个包含所有预生成日期的表。我认为datediff必须介于0和9之间,否则也会计算负datediff。此平均值“移动”如何?现在只是一个静态平均值计算。移动的部分是它每天都在计算。是的,MySQL支持窗口函数很好。我喜欢移动平均的窗口链接: