Group by data intervals Group by data intervals postgresql postgresql

Group by data intervals


WITH t AS (   SELECT ts, (random()*100)::int AS bandwidth   FROM   generate_series('2012-09-01', '2012-09-04', '1 minute'::interval) ts   )SELECT date_trunc('hour', ts) AS hour_stump      ,(extract(minute FROM ts)::int / 15) AS min15_slot      ,count(*) AS rows_in_timeslice               -- optional      ,sum(bandwidth) AS sum_bandwidthFROM   tWHERE  ts >= '2012-09-02 00:00:00+02'::timestamptz -- user's time rangeAND    ts <  '2012-09-03 00:00:00+02'::timestamptz -- careful with borders GROUP  BY 1, 2ORDER  BY 1, 2;

The CTE t provides data like your table might hold: one timestamp ts per minute with a bandwidth number. (You don't need that part, you work with your table instead.)

Here is a very similar solution for a very similar question - with detailed explanation how this particular aggregation works:

Here is a similar solution for a similar question concerning running sums - with detailed explanation and links for the various functions used:

Additional question in comment

WITH -- same as above ...SELECT DISTINCT ON (1,2)       date_trunc('hour', ts) AS hour_stump      ,(extract(minute FROM ts)::int / 15) AS min15_slot      ,bandwidth AS bandwith_sample_at_min15FROM   tWHERE  ts >= '2012-09-02 00:00:00+02'::timestamptzAND    ts <  '2012-09-03 00:00:00+02'::timestamptzORDER  BY 1, 2, ts DESC;

Retrieves one un-aggregated sample per 15 minute interval - from the last available row in the window. This will be the 15th minute if the row is not missing. Crucial parts are DISTINCT ON and ORDER BY.
More information about the used technique here:


select    date_trunc('hour', d) +     (((extract(minute from d)::integer / 5 * 5)::text) || ' minute')::interval    as "from",    date_trunc('hour', d) +     ((((extract(minute from d)::integer / 5 + 1) * 5)::text) || ' minute')::interval    - '1 second'::interval    as "to",    sum(random() * 1000) as bandwidthfrom     generate_series('2012-01-01', '2012-01-31', '1 minute'::interval) s(d)group by 1, 2order by 1, 2;

That for 5 minutes ranges. For 15 minutes divide by 15.