2010-06-21 14 views
32

Tengo una tabla (MySQL) que captura muestras cada n segundos. La tabla tiene muchas columnas, pero todo lo que importa para esto es dos: una marca de tiempo (del tipo TIMESTAMP) y una cuenta (del tipo INT).SELECCIONAR/AGRUPAR POR - segmentos de tiempo (10 segundos, 30 segundos, etc.)

Lo que me gustaría hacer es obtener sumas y promedios de la columna de recuento en un intervalo de veces. Por ejemplo, tengo muestras cada 2 segundos registradas, pero me gustaría la suma de la columna de conteo para todas las muestras en una ventana de 10 segundos o 30 segundos para todas las muestras.

He aquí un ejemplo de los datos:

 
+---------------------+-----------------+ 
| time_stamp   | count   | 
+---------------------+-----------------+ 
| 2010-06-15 23:35:28 |    1 | 
| 2010-06-15 23:35:30 |    1 | 
| 2010-06-15 23:35:30 |    1 | 
| 2010-06-15 23:35:30 |    942 | 
| 2010-06-15 23:35:30 |    180 | 
| 2010-06-15 23:35:30 |    4 | 
| 2010-06-15 23:35:30 |    52 | 
| 2010-06-15 23:35:30 |    12 | 
| 2010-06-15 23:35:30 |    1 | 
| 2010-06-15 23:35:30 |    1 | 
| 2010-06-15 23:35:33 |   1468 | 
| 2010-06-15 23:35:33 |    247 | 
| 2010-06-15 23:35:33 |    1 | 
| 2010-06-15 23:35:33 |    81 | 
| 2010-06-15 23:35:33 |    16 | 
| 2010-06-15 23:35:35 |   1828 | 
| 2010-06-15 23:35:35 |    214 | 
| 2010-06-15 23:35:35 |    75 | 
| 2010-06-15 23:35:35 |    8 | 
| 2010-06-15 23:35:37 |   1799 | 
| 2010-06-15 23:35:37 |    24 | 
| 2010-06-15 23:35:37 |    11 | 
| 2010-06-15 23:35:37 |    2 | 
| 2010-06-15 23:35:40 |    575 | 
| 2010-06-15 23:35:40 |    1 | 
| 2010-06-17 10:39:35 |    2 | 
| 2010-06-17 10:39:35 |    2 | 
| 2010-06-17 10:39:35 |    1 | 
| 2010-06-17 10:39:35 |    2 | 
| 2010-06-17 10:39:35 |    1 | 
| 2010-06-17 10:39:40 |    35 | 
| 2010-06-17 10:39:40 |    19 | 
| 2010-06-17 10:39:40 |    37 | 
| 2010-06-17 10:39:42 |    64 | 
| 2010-06-17 10:39:42 |    3 | 
| 2010-06-17 10:39:42 |    31 | 
| 2010-06-17 10:39:42 |    7 | 
| 2010-06-17 10:39:42 |    246 | 
+---------------------+-----------------+ 

La salida me gustaría (basado en los datos anteriores) debería tener este aspecto:

 
+---------------------+-----------------+ 
| 2010-06-15 23:35:00 |    1 | # This is the sum for the 00 - 30 seconds range 
| 2010-06-15 23:35:30 |   7544 | # This is the sum for the 30 - 60 seconds range 
| 2010-06-17 10:39:35 |    450 | # This is the sum for the 30 - 60 seconds range 
+---------------------+-----------------+ 

he utilizado GROUP BY para reunir estos números por segundo, o por minuto, pero parece que no puedo entender la sintaxis para obtener el sub-minuto o el rango de segundos de los comandos GROUP BY para que funcionen correctamente.

Principalmente voy a utilizar esta consulta para transferir datos de esta tabla a otra tabla.

Gracias!

Respuesta

58

GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 30

o decir por alguna razón quería agruparlos en intervalos de 20 segundos sería DIV 20 etc. Para cambiar los límites entre GROUP BY valores que se podría utilizar

GROUP BY (UNIX_TIMESTAMP(time_stamp) + r) DIV 30

donde r es un entero literal no negativo menos de 30. Entonces

GROUP BY (UNIX_TIMESTAMP(time_stamp) + 5) DIV 30

debe darle sumas entre hh: mm: 05 y hh: mm: 35 y entre hh: mm: 35 y hh: mm + 1: 05.

+0

¡Perfecto! Eso hizo * exactamente * lo que necesitaba! ¡Gracias un montón! –

6

Intenté la solución de Hammerite en mi proyecto, pero no funcionó bien cuando faltaban muestras de la serie. Aquí está un ejemplo de la consulta que se supone que para seleccionar marca de tiempo (ts), el nombre de usuario y una medida promedio de metric_table y agrupar los resultados por intervalos de tiempo de 27 minutos:

select 
    min(ts), 
    user_name, 
    sum(measure)/27 
from metric_table 
where 
    ts between date_sub('2015-03-17 00:00:00', INTERVAL 2160 MINUTE) and '2015-03-17 00:00:00' 

group by unix_timestamp(ts) div 1620, user_name 
order by ts, user_name 
; 

Nota: 27 minutos (en el selecto) = 1620 segundos (en grupo por), 2160 minutos = 3 días (ese es el intervalo de tiempo)

Cuando ejecuté esta consulta en una serie temporal donde las muestras se registraron irregularmente (en otras palabras: para una marca de tiempo dada no había garantía para encontrar valores de medición para todos los nombres de usuario) los resultados no fueron sellados de acuerdo con el intervalo (no se colocaron cada 27 minutos). Sospecho que se debió a que min (ts) devolvió una marca de tiempo en algunos grupos que era mayor que el piso esperado (intervalo ts0 + i *). Modifiqué la consulta anterior a este:

select 
    from_unixtime(unix_timestamp(ts) - unix_timestamp(ts) mod 1620) as ts1, 
    user_name, 
    sum(measure)/27 
from metric_table 
where 
    ts between date_sub('2015-03-17 00:00:00', INTERVAL 2160 MINUTE) and '2015-03-17 00:00:00' 

group by ts1, user_name 
order by ts1, user_name 
; 

y funciona bien incluso cuando faltan las muestras. Creo que es porque una vez que el tiempo matemático se mueve para seleccionar, garantiza que ts1 se alineará con los pasos de tiempo.

+0

Gracias por traer esto para arriba, me ayudaron mucho! – citysurrounded

+0

¡Cosas maravillosas! Todo lo que necesito ahora es una manera para que pueda grabar una fila "cero" para cuando no hay muestras en ese momento balde ... –

+0

@DanielRhodes vez la figura que uno? –

0

muy extraño, pero usando la solución aquí:

Average of data for every 5 minutes in the given times

Podemos sugerir algo como:

select convert(
(min(dt_record) div 50)*50 - 20*((convert(min(dt_record), datetime) div 50) mod 2), 

de fecha y hora) como dt, avg (1das4hrz) de meteor-m2_msgi donde dt_record> = '2016-11-13 05:00:00' y dt_record < '2016-11-14 00:00:00' group by convert (dt_record, datetime) div 50;

select (
convert(
min(dt_record), datetime) div 50)*50 - 20*(
(convert(min(dt_record), datetime) div 50) mod 2 
) as dt, 
avg(column) from `your_table` 
where dt_record>='2016-11-13 05:00:00' 
and dt_record < '2016-11-14 00:00:00' 
group by convert(dt_record, datetime) div 50; 

50 se debe a un medio de NORMAL minuto tiene 30 segundos, mientras que 'INTEGER FORM.FECHA' nos supone que debe dividir por 50

2

Otra solución.

para promediar sobre cualquier intervalo lo desea, puede convertir su marca de tiempo dt de grupo y por el módulo por su intervalo de 7 segundos (en el ejemplo).

select FROM_UNIXTIME(
    UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7 
) as dt, avg(1das4hrz) from `meteor-m2_msgi` 
where dt_record>='2016-11-13 05:00:00' 
and dt_record < '2016-11-13 05:02:00' 
group by FROM_UNIXTIME(
    UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7); 

Para mostrar cómo funciona, preparo una solicitud que muestra los cálculos.

select dt_record, minute(dt_record) as mm, SECOND(dt_record) as ss, 
UNIX_TIMESTAMP(dt_record) as uxt, UNIX_TIMESTAMP(dt_record) mod 7 as ux7, 
FROM_UNIXTIME(
    UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7) as dtsub, 
column from `yourtable` where dt_record>='2016-11-13 05:00:00' 
and dt_record < '2016-11-13 05:02:00'; 

+---------------------+--------------------+ 
| dt     | avg(column)  | 
+---------------------+--------------------+ 
| 2016-11-13 04:59:43 | 25434.85714285714 | 
| 2016-11-13 05:00:42 | 5700.728813559322 | 
| 2016-11-13 05:01:41 | 950.1016949152543 | 
| 2016-11-13 05:02:40 | 4671.220338983051 | 
| 2016-11-13 05:03:39 | 25468.728813559323 | 
| 2016-11-13 05:04:38 | 43883.52542372881 | 
| 2016-11-13 05:05:37 | 24589.338983050846 | 
+---------------------+--------------------+ 


+---------------------+-----+-----+------------+------+---------------------+----------+ 
| dt_record   | mm | ss | uxt  | ux7 | dtsub    | column | 
+---------------------+------+-----+------------+------+---------------------+----------+ 
| 2016-11-13 05:00:00 | 0 | 0 | 1479002400 | 1 | 2016-11-13 04:59:59 | 36137 | 
| 2016-11-13 05:00:01 | 0 | 1 | 1479002401 | 2 | 2016-11-13 04:59:59 | 36137 | 
| 2016-11-13 05:00:02 | 0 | 2 | 1479002402 | 3 | 2016-11-13 04:59:59 | 36137 | 
| 2016-11-13 05:00:03 | 0 | 3 | 1479002403 | 4 | 2016-11-13 04:59:59 | 34911 |  
| 2016-11-13 05:00:04 | 0 | 4 | 1479002404 | 5 | 2016-11-13 04:59:59 | 34911 | 
| 2016-11-13 05:00:05 | 0 | 5 | 1479002405 | 6 | 2016-11-13 04:59:59 | 34911 | 
| 2016-11-13 05:00:06 | 0 | 6 | 1479002406 | 0 | 2016-11-13 05:00:06 | 33726 | 
| 2016-11-13 05:00:07 | 0 | 7 | 1479002407 | 1 | 2016-11-13 05:00:06 | 32581 | 
| 2016-11-13 05:00:08 | 0 | 8 | 1479002408 | 2 | 2016-11-13 05:00:06 | 32581 | 
| 2016-11-13 05:00:09 | 0 | 9 | 1479002409 | 3 | 2016-11-13 05:00:06 | 31475 | 
+---------------------+-----+-----+------------+------+---------------------+----------+ 

¿Alguien puede sugerir algo más rápido?

Cuestiones relacionadas