web-dev-qa-db-fra.com

Regroupement dans un intervalle de 5 minutes dans une plage de temps

J'ai quelques difficultés avec les commandes MySQL que je veux faire. 

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

Ceci est ma déclaration de sortie actuelle.

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

Comment les regrouper en résultats d'intervalle de 5 minutes?

Je veux que ma sortie soit comme

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 
68
sky

Cela fonctionne à chaque intervalle.

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
110
boecko

Vous devriez plutôt utiliser GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 300 au lieu de round (../ 300) en raison des arrondis. J'ai constaté que certains enregistrements sont comptés dans deux ensembles de résultats groupés. 

28
pHiL

Pour postgres, j’ai trouvé plus facile et plus précis d’utiliser le 

date_trunc

fonction, comme:

select name, sum(count), date_trunc('minute',timestamp) as timestamp
FROM table
WHERE xxx
GROUP BY name,date_trunc('minute',timestamp)
ORDER BY timestamp

Vous pouvez fournir diverses résolutions comme «minute», «heure», «jour», etc. à date_trunc.

26
Scott Persinger

je suis tombé sur le même problème. 

J'ai trouvé qu'il est facile de grouper par n'importe quel intervalle de minute est divisez simplement Epoch par quelques minutes, puis arrondissez ou utilisez le sol pour éviter le reste. Donc, si vous voulez obtenir un intervalle dans 5 minutes, vous utiliserez 300 secondes .

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
 </ pre> 

</ code> 

 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 

Cela retournera les données correctement groupe par intervalle de minutes sélectionné; Cependant, il ne renverra pas les intervalles qui ne contiennent aucune donnée. Pour obtenir ces intervalles vides, nous pouvons utiliser la fonction generate_series

SELECT generate_series(MIN(date_trunc('hour',timestamp_column)),
max(date_trunc('minute',timestamp_column)),'5m') as interval_alias FROM 
TABLE_NAME
 </ pre> 

</ code> Résultat:

 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 

Maintenant, pour obtenir le résultat avec un intervalle sans occurrences, il suffit de outer joindre les deux jeux de résultats

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
 </ pre> 

sur series.minute = cnt.interval_alias

</ code> Le résultat final comprendra la série avec tous les intervalles de 5 minutes, même ceux sans valeur. 

 compte d'intervalles 
------------------- ---- 
 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 

L'intervalle peut être facilement modifié en ajustant le dernier paramètre de generate_series. Dans notre cas, nous utilisons '5m' mais cela pourrait être tout intervalle souhaité. 

23
Nestor Martinez

La requête sera quelque chose comme:

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
10
WASD42

Vous devrez probablement diviser votre horodatage en ymd: HM et utiliser DIV 5 pour fractionner les minutes en bacs de 5 minutes - quelque chose comme:

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

... et ensuite, la sortie dans le code client apparaîtra comme vous le souhaitez. Ou bien, vous pouvez construire la chaîne de date entière en utilisant l'opérateur sql concat au lieu d'obtenir des colonnes séparées, si vous le souhaitez.

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'))

... et puis groupe sur ça

4
Bill Dueber

Celui-ci, ça va:

select 
    from_unixtime(unix_timestamp(timestamp) - unix_timestamp(timestamp) mod 300) as ts,  
    sum(value)
from group_interval 
group by ts 
order by ts
;
1
mac13k

Je ne sais pas si vous en avez encore besoin.

SELECT FROM_UNIXTIME(FLOOR((UNIX_TIMESTAMP(timestamp))/300)*300) AS t,timestamp,count(1) as c from users GROUP BY t ORDER BY t;

2016-10-29 19:35:00 | 2016-10-29 19:35:50 | 4 | 

2016-10-29 19:40:00 | 2016-10-29 19:40:37 | 5 | 

2016-10-29 19:45:00 | 2016-10-29 19:45:09 | 6 | 

2016-10-29 19:50:00 | 2016-10-29 19:51:14 | 4 |

2016-10-29 19:55:00 | 2016-10-29 19:56:17 | 1 |

1
user7088930

J'ai découvert qu'avec MySQL, la requête correcte est probablement la suivante:

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

Laissez-moi savoir ce que vous pensez.

0
EBAH
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))
0
gerrit bosua