Calculando os valores médios ao longo seções de data / hora
Pergunta
Problema:
Eu tenho um banco de dados de leituras de sensores com um timestamp para o tempo o sensor foi lido. Basicamente, parece que isso:
Sensor | Timestamp | Value
Agora eu quero fazer um gráfico de dados e eu quero fazer vários gráficos diferentes. Digamos que eu queira um para o último dia, um para a última semana e uma para o mês passado. A resolução de cada gráfico será muito diferente para o dia-a resolução gráfico seria de 1 minuto. Para o gráfico semana seria uma hora, e para o gráfico mês seria um dia, ou um quarto de um dia.
Então, eu gostaria de uma saída que é a média de cada resolução (por exemplo. Dia = Média sobre o minuto, Semana = Média sobre a hora e assim por diante)
Ex:
Sensor | Start | End | Average
Como posso fazer isso com facilidade e rapidez no MySQL? Eu suspeito que invoves criação de uma tabela temporária ou tipos e juntando os dados do sensor com que para obter os valores médios do sensor? Mas o meu conhecimento de mySQL é limitado na melhor das hipóteses.
Existe uma maneira muito inteligente de fazer isso?
Solução
SELECT DAY(Timestamp), HOUR(Timestamp), MINUTE(Timestamp), AVG(value)
FROM mytable
GROUP BY
DAY(Timestamp), HOUR(Timestamp), MINUTE(Timestamp) WITH ROLLUP
cláusula WITH ROLLUP
aqui produz linhas extras com as médias para cada HOUR
e DAY
, como este:
SELECT DAY(ts), HOUR(ts), MINUTE(ts), COUNT(*)
FROM (
SELECT CAST('2009-06-02 20:00:00' AS DATETIME) AS ts
UNION ALL
SELECT CAST('2009-06-02 20:30:00' AS DATETIME) AS ts
UNION ALL
SELECT CAST('2009-06-02 21:30:00' AS DATETIME) AS ts
UNION ALL
SELECT CAST('2009-06-03 21:30:00' AS DATETIME) AS ts
) q
GROUP BY
DAY(ts), HOUR(ts), MINUTE(ts) WITH ROLLUP
2, 20, 0, 1 2, 20, 30, 1 2, 20, NULL, 2 2, 21, 30, 1 2, 21, NULL, 1 2, NULL, NULL, 3 3, 21, 30, 1 3, 21, NULL, 1 3, NULL, NULL, 1 NULL, NULL, NULL, 4
2, 20, NULL, 2
aqui significa que COUNT(*)
é 2
para DAY = 2
, HOUR = 20
e todos os minutos.
Outras dicas
Não é bem a tabela de resultados que você queria, mas aqui é um fermento para fazer uma resolução de 1 minuto:
SELECT sensor,minute(timestamp),avg(value)
FROM table
WHERE <time period specifier limits to a single hour>
GROUP BY sensor, minute(timestamp)
Eu tenho código usado muito semelhante a esta (não testado, mas ele está tomando a partir do código de trabalho)
definir as variáveis:
$seconds = 3600;
$start = mktime(...); // say 2 hrs ago
$end = .... // 1 hour after $start
, em seguida, executar a consulta ??p>
SELECT MAX(`when`) AS top_When, MIN(`when`) AS low_When,
ROUND(AVG(sensor)) AS Avg_S,
(MAX(`when`) - MIN(`when`)) AS dur, /* the duration in seconds of the actual period */
((floor(UNIX_TIMESTAMP(`when`) / $seconds)) * $seconds) as Epoch
FROM `sensor_stats`
WHERE `when` >= '$start' AND `when` <= '$end' and duration=30
GROUP BY Epoch/*((floor(UNIX_TIMESTAMP(`when`) / $seconds)) * $seconds)*/
A vantagem disso é que você pode ter o que períodos de tempo que você quiser -. E nem mesmo obrigados a tê-los em 'números redondos', como um relógio horas completo (até mesmo um relógio minutos, 0-59)