2013-04-20 4 views
4

Good Day,Расчет скользящего среднего MySQL?

Для расчета 9-дневной скользящей средней используется следующий код.

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

Но это не сработает, потому что оно сначала вычисляет все возвращенные поля до того, как вызывается предел. Другими словами, он будет вычислять все закрытые ранее или равные этой дате, а не только последние 9.

Так что мне нужно рассчитать SUM из возвращенного select, а не рассчитать его прямо.

IE. Выберите SUM из SELECT ...

Теперь, как я буду заниматься этим, и это очень дорого или есть лучший способ?

+0

Как это среднее «движение»? – Strawberry

+0

Это просто статический средний расчет. Движущаяся часть состоит в том, что она рассчитана каждый день. – surfer190

ответ

4

использовать что-то вроде

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 порядке, а затем вы avg, sum вверх эти строки возвращаются.

Причина query предоставленных Вами не работает из-за тот факт, что sum рассчитывается первым и пункт LIMIT применяется после sum уже вычислен, давая вам sum все строки, присутствующих

+5

. , Это возвращает одно значение. Скользящее среднее относится к отдельному значению для каждой даты для «n» записей. –

+0

Да, я предположил, что OP хочет перемещение avg для определенного дня, '2002-07-05' – Akash

+0

Это решение работает, если задано конкретное имя_ид, есть ли способ получить скользящую среднюю для каждого name_id в таблице? Таким образом, вывод будет таблицей скользящих средних для каждого name_id – user6890

8

Если вы хотите скользящее среднее значение для каждой даты, то попробуйте следующее:

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

+3

@ surfer100 Нечетный то, что это не принятый ответ – Strawberry

+0

Нападение на эту старую нить, потому что я ищу тот же ответ, используя временные метки эпохи. Проблема здесь в том, что это не учитывает выходные. – fractal5

0

Этот запрос быстро:

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 значений, это утомительно писать, но стоит усилий. Скорость близка к упорядоченному выбору.

0

Иным метод сделать таблицу:

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 
Смежные вопросы