Trek 30 minuten af van het einde (of begin) van elk tijdbereik. Ga dan in principe verder zoals beschreven in mijn verwezen "eenvoudige" antwoord (overal aanpassen voor de 30 min in de goede richting). Bereiken korter dan 30 minuten worden a priori geëlimineerd - wat logisch is omdat deze nooit deel kunnen uitmaken van een periode van 30 minuten met continue overlap. Maakt de zoekopdracht ook sneller.
Berekening voor alle dagen in okt 2019 (voorbeeldbereik):
WITH range AS (SELECT timestamp '2019-10-01' AS start_ts -- incl. lower bound
, timestamp '2019-11-01' AS end_ts) -- excl. upper bound
, cte AS (
SELECT userid, starttime
-- default to current timestamp if NULL
, COALESCE(endtime, localtimestamp) - interval '30 min' AS endtime
FROM usersessions, range r
WHERE starttime < r.end_ts -- count overlaps *starting* in outer time range
AND (endtime >= r.start_ts + interval '30 min' OR endtime IS NULL)
)
, ct AS (
SELECT ts, sum(ct) OVER (ORDER BY ts, ct) AS session_ct
FROM (
SELECT endtime AS ts, -1 AS ct FROM cte
UNION ALL
SELECT starttime , +1 FROM cte
) sub
)
SELECT ts::date, max(session_ct) AS max_concurrent_sessions
FROM ct, range r
WHERE ts >= r.start_ts
AND ts < r.end_ts -- crop outer time range
GROUP BY ts::date
ORDER BY 1;
db<>fiddle hier
Houd er rekening mee dat LOCALTIMESTAMP
hangt af van de tijdzone van de huidige sessie. Overweeg om timestamptz in uw tabel te gebruiken en CURRENT_TIMESTAMP
in plaats van. Zie: