Calcular valores promedio en secciones de fecha/hora
Pregunta
Problema:
Tengo una base de datos de lecturas de sensores con una marca de tiempo del momento en que se leyó el sensor.Básicamente se ve así:
Sensor | Timestamp | Value
Ahora quiero hacer un gráfico a partir de estos datos y quiero hacer varios gráficos diferentes.Digamos que quiero uno para el último día, uno para la última semana y otro para el último mes.La resolución de cada gráfico será diferente, por lo que para el gráfico diurno la resolución sería de 1 minuto.Para el gráfico semanal sería una hora y para el gráfico mensual sería un día o un cuarto de día.
Entonces me gustaría un resultado que sea el promedio de cada resolución (por ejemplo.Día = Promedio por minuto, Semana = Promedio por hora, etc.)
Ex:
Sensor | Start | End | Average
¿Cómo hago esto fácil y rápidamente en mySQL?Sospecho que implica crear una tabla o clasificación temporal y unir los datos del sensor para obtener los valores promedio del sensor.Pero mi conocimiento de MySQL es, en el mejor de los casos, limitado.
¿Existe una forma realmente inteligente de hacer esto?
Solución
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
aquí produce filas adicionales con promedios de cada HOUR
y DAY
, como esto:
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
aquí significa que es COUNT(*)
2
para DAY = 2
, HOUR = 20
y todos los minutos.
Otros consejos
No es exactamente la tabla de resultados que quería, pero aquí hay un motor de arranque para hacer una resolución 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)
He usado un código muy similar a este (no probado, pero está tomado del código de trabajo)
establecer las variables:
$seconds = 3600;
$start = mktime(...); // say 2 hrs ago
$end = .... // 1 hour after $start
luego ejecuta la consulta
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)*/
La ventaja de esto es que puede tener los períodos de tiempo que desee, y ni siquiera es necesario tenerlos en "números redondos", como una hora de reloj completa (incluso un minuto de reloj, 0-59).