PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Postgresql SQL GROUP BY intervalle de temps avec une précision arbitraire (jusqu'à millisecondes)

Vous pouvez générer une table de "buckets" en ajoutant des intervalles créés par generate_series(). Cette instruction SQL générera une table de tranches de cinq minutes pour le premier jour (la valeur de min(measured_at) ) dans vos données.

select 
  (select min(measured_at)::date from measurements) + ( n    || ' minutes')::interval start_time,
  (select min(measured_at)::date from measurements) + ((n+5) || ' minutes')::interval end_time
from generate_series(0, (24*60), 5) n

Enveloppez ça dans une expression de table commune, et vous pouvez joindre et grouper dessus comme s'il s'agissait d'une table de base.

with five_min_intervals as (
  select 
    (select min(measured_at)::date from measurements) + ( n    || ' minutes')::interval start_time,
    (select min(measured_at)::date from measurements) + ((n+5) || ' minutes')::interval end_time
  from generate_series(0, (24*60), 5) n
)
select f.start_time, f.end_time, avg(m.val) avg_val 
from measurements m
right join five_min_intervals f 
        on m.measured_at >= f.start_time and m.measured_at < f.end_time
group by f.start_time, f.end_time
order by f.start_time

Le regroupement par un nombre arbitraire de secondes est similaire - utilisez date_trunc() .

Une utilisation plus générale de generate_series() vous permet d'éviter de deviner la limite supérieure pour les compartiments de cinq minutes. En pratique, vous construiriez probablement ceci comme une vue ou une fonction. Vous pourriez obtenir de meilleures performances à partir d'une table de base.

select 
  (select min(measured_at)::date from measurements) + ( n    || ' minutes')::interval start_time,
  (select min(measured_at)::date from measurements) + ((n+5) || ' minutes')::interval end_time
from generate_series(0, ((select max(measured_at)::date - min(measured_at)::date from measurements) + 1)*24*60, 5) n;