Tengo algunas dificultades con los comandos mySQL que quiero hacer.
SELECT a.timestamp, name, count(b.name)
FROM time a, id b
WHERE a.user = b.user
AND a.id = b.id
AND b.name = 'John'
AND a.timestamp BETWEEN '2010-11-16 10:30:00' AND '2010-11-16 11:00:00'
GROUP BY a.timestamp
Esta es mi declaración de salida actual.
timestamp name count(b.name)
------------------- ---- -------------
2010-11-16 10:32:22 John 2
2010-11-16 10:35:12 John 7
2010-11-16 10:36:34 John 1
2010-11-16 10:37:45 John 2
2010-11-16 10:48:26 John 8
2010-11-16 10:55:00 John 9
2010-11-16 10:58:08 John 2
¿Cómo los agrupo en resultados con intervalos de 5 minutos?
Quiero que mi salida sea como
timestamp name count(b.name)
------------------- ---- -------------
2010-11-16 10:30:00 John 2
2010-11-16 10:35:00 John 10
2010-11-16 10:40:00 John 0
2010-11-16 10:45:00 John 8
2010-11-16 10:50:00 John 0
2010-11-16 10:55:00 John 11
Respuestas:
Esto funciona con todos los intervalos.
PostgreSQL
SELECT TIMESTAMP WITH TIME ZONE 'epoch' + INTERVAL '1 second' * round(extract('epoch' from timestamp) / 300) * 300 as timestamp, name, count(b.name) FROM time a, id WHERE … GROUP BY round(extract('epoch' from timestamp) / 300), name
MySQL
SELECT timestamp, -- not sure about that name, count(b.name) FROM time a, id WHERE … GROUP BY UNIX_TIMESTAMP(timestamp) DIV 300, name
fuente
Me encontré con el mismo problema.
Descubrí que es fácil agrupar por cualquier intervalo de minutos, simplemente dividiendo la época por minutos en la cantidad de segundos y luego redondeando o usando el piso para obtener el resto. Entonces, si desea obtener un intervalo en 5 minutos , usaría 300 segundos .
SELECT COUNT(*) cnt, to_timestamp(floor((extract('epoch' from timestamp_column) / 300 )) * 300) AT TIME ZONE 'UTC' as interval_alias FROM TABLE_NAME GROUP BY interval_alias
interval_alias cnt ------------------- ---- 2010-11-16 10:30:00 2 2010-11-16 10:35:00 10 2010-11-16 10:45:00 8 2010-11-16 10:55:00 11
Esto devolverá los datos agrupados correctamente por el intervalo de minutos seleccionado; sin embargo, no devolverá los intervalos que no contengan ningún dato. Para obtener esos intervalos vacíos podemos usar la función generate_series .
SELECT generate_series(MIN(date_trunc('hour',timestamp_column)), max(date_trunc('minute',timestamp_column)),'5m') as interval_alias FROM TABLE_NAME
Resultado:
interval_alias ------------------- 2010-11-16 10:30:00 2010-11-16 10:35:00 2010-11-16 10:40:00 2010-11-16 10:45:00 2010-11-16 10:50:00 2010-11-16 10:55:00
Ahora, para obtener el resultado con intervalo con cero ocurrencias, simplemente unimos ambos conjuntos de resultados .
SELECT series.minute as interval, coalesce(cnt.amnt,0) as count from ( SELECT count(*) amnt, to_timestamp(floor((extract('epoch' from timestamp_column) / 300 )) * 300) AT TIME ZONE 'UTC' as interval_alias from TABLE_NAME group by interval_alias ) cnt RIGHT JOIN ( SELECT generate_series(min(date_trunc('hour',timestamp_column)), max(date_trunc('minute',timestamp_column)),'5m') as minute from TABLE_NAME ) series on series.minute = cnt.interval_alias
El resultado final incluirá la serie con todos los intervalos de 5 minutos, incluso aquellos que no tienen valores.
interval count ------------------- ---- 2010-11-16 10:30:00 2 2010-11-16 10:35:00 10 2010-11-16 10:40:00 0 2010-11-16 10:45:00 8 2010-11-16 10:50:00 0 2010-11-16 10:55:00 11
El intervalo se puede cambiar fácilmente ajustando el último parámetro de generate_series. En nuestro caso usamos '5m' pero podría ser cualquier intervalo que queramos.
fuente
Debería usar en
GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 300
lugar de redondear (../ 300) debido al redondeo. Descubrí que algunos registros se cuentan en dos conjuntos de resultados agrupados.fuente
DIV
en MySQL hay unafloor()
división flotante que es segura conBIGINT
s.Para postgres , encontré más fácil y más preciso usar el
date_trunc
función, como:
select name, sum(count), date_trunc('minute',timestamp) as timestamp FROM table WHERE xxx GROUP BY name,date_trunc('minute',timestamp) ORDER BY timestamp
Puede proporcionar varias resoluciones como 'minuto', 'hora', 'día', etc. a date_trunc.
fuente
5
aquí el intervalo de 5 minutos?La consulta será algo como:
SELECT DATE_FORMAT( MIN(timestamp), '%d/%m/%Y %H:%i:00' ) AS tmstamp, name, COUNT(id) AS cnt FROM table GROUP BY ROUND(UNIX_TIMESTAMP(timestamp) / 300), name
fuente
Probablemente tendrá que dividir su marca de tiempo en ymd: HM y usar DIV 5 para dividir los minutos en contenedores de 5 minutos, algo así como
select year(a.timestamp), month(a.timestamp), hour(a.timestamp), minute(a.timestamp) DIV 5, name, count(b.name) FROM time a, id b WHERE a.user = b.user AND a.id = b.id AND b.name = 'John' AND a.timestamp BETWEEN '2010-11-16 10:30:00' AND '2010-11-16 11:00:00' GROUP BY year(a.timestamp), month(a.timestamp), hour(a.timestamp), minute(a.timestamp) DIV 12
... y luego coloque el resultado en el código del cliente para que aparezca de la forma que desee. O puede crear la cadena de fecha completa utilizando el operador sql concat en lugar de obtener columnas separadas, si lo desea.
select concat(year(a.timestamp), "-", month(a.timestamp), "-" ,day(a.timestamp), " " , lpad(hour(a.timestamp),2,'0'), ":", lpad((minute(a.timestamp) DIV 5) * 5, 2, '0'))
... y luego agrupar en eso
fuente
No estoy seguro de si aún lo necesita.
SELECT FROM_UNIXTIME(FLOOR((UNIX_TIMESTAMP(timestamp))/300)*300) AS t,timestamp,count(1) as c from users GROUP BY t ORDER BY t;
fuente
Que tal este:
select from_unixtime(unix_timestamp(timestamp) - unix_timestamp(timestamp) mod 300) as ts, sum(value) from group_interval group by ts order by ts ;
fuente
Descubrí que con MySQL probablemente la consulta correcta es la siguiente:
SELECT SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300, '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) AS ts_CEILING, SUM(value) FROM group_interval GROUP BY SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300, '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) ORDER BY SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300, '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) DESC
Déjame saber lo que piensas.
fuente
select CONCAT(CAST(CREATEDATE AS DATE),' ',datepart(hour,createdate),':',ROUNd(CAST((CAST((CAST(DATEPART(MINUTE,CREATEDATE) AS DECIMAL (18,4)))/5 AS INT)) AS DECIMAL (18,4))/12*60,2)) AS '5MINDATE' ,count(something) from TABLE group by CONCAT(CAST(CREATEDATE AS DATE),' ',datepart(hour,createdate),':',ROUNd(CAST((CAST((CAST(DATEPART(MINUTE,CREATEDATE) AS DECIMAL (18,4)))/5 AS INT)) AS DECIMAL (18,4))/12*60,2))
fuente