Skip to main content
added 18 characters in body
Source Link
Laurenz Albe
  • 56.4k
  • 4
  • 50
  • 82

Generate a series of timestamp ranges, join with your data, calculate the overlap and aggregate:

SELECT user_id,
       bucket,
       coalesce(sum(upper(inters) - lower(inters)), 0) AS duration
FROM (SELECT user_id,
             lower(ranges.r) AS bucket,
             tsrange(tab.start, tab.end, '[)') * ranges.r AS inters
      FROM (SELECT tsrange(st, st + '1 hour'::interval, '[)') AS r
            FROM generate_series(
                    '2021-01-01 00:00:00'::timestamp,
                    '2021-12-31 23:00:00'::timestamp,
                    '1 hour'::interval
                 ) AS g(st)
           ) AS ranges
         LEFT JOIN tab
            ON tsrange(tab.start, tab.end, '[)') * ranges.r <> 'empty'
     ) AS intersections
GROUP BY tab.user_id, bucket;

Generate a series of timestamp ranges, join with your data, calculate the overlap and aggregate:

SELECT user_id,
       bucket,
       sum(upper(inters) - lower(inters)) AS duration
FROM (SELECT user_id,
             lower(ranges.r) AS bucket,
             tsrange(tab.start, tab.end, '[)') * ranges.r AS inters
      FROM (SELECT tsrange(st, st + '1 hour'::interval, '[)') AS r
            FROM generate_series(
                    '2021-01-01 00:00:00'::timestamp,
                    '2021-12-31 23:00:00'::timestamp,
                    '1 hour'::interval
                 ) AS g(st)
           ) AS ranges
         JOIN tab
            ON tsrange(tab.start, tab.end, '[)') * ranges.r <> 'empty'
     ) AS intersections
GROUP BY tab.user_id, bucket;

Generate a series of timestamp ranges, join with your data, calculate the overlap and aggregate:

SELECT user_id,
       bucket,
       coalesce(sum(upper(inters) - lower(inters)), 0) AS duration
FROM (SELECT user_id,
             lower(ranges.r) AS bucket,
             tsrange(tab.start, tab.end, '[)') * ranges.r AS inters
      FROM (SELECT tsrange(st, st + '1 hour'::interval, '[)') AS r
            FROM generate_series(
                    '2021-01-01 00:00:00'::timestamp,
                    '2021-12-31 23:00:00'::timestamp,
                    '1 hour'::interval
                 ) AS g(st)
           ) AS ranges
         LEFT JOIN tab
            ON tsrange(tab.start, tab.end, '[)') * ranges.r <> 'empty'
     ) AS intersections
GROUP BY tab.user_id, bucket;
Source Link
Laurenz Albe
  • 56.4k
  • 4
  • 50
  • 82

Generate a series of timestamp ranges, join with your data, calculate the overlap and aggregate:

SELECT user_id,
       bucket,
       sum(upper(inters) - lower(inters)) AS duration
FROM (SELECT user_id,
             lower(ranges.r) AS bucket,
             tsrange(tab.start, tab.end, '[)') * ranges.r AS inters
      FROM (SELECT tsrange(st, st + '1 hour'::interval, '[)') AS r
            FROM generate_series(
                    '2021-01-01 00:00:00'::timestamp,
                    '2021-12-31 23:00:00'::timestamp,
                    '1 hour'::interval
                 ) AS g(st)
           ) AS ranges
         JOIN tab
            ON tsrange(tab.start, tab.end, '[)') * ranges.r <> 'empty'
     ) AS intersections
GROUP BY tab.user_id, bucket;