Khấu trừ 30 phút kể từ khi kết thúc (hoặc bắt đầu) mỗi khoảng thời gian. Sau đó, về cơ bản hãy tiếp tục như đã nêu trong câu trả lời "đơn giản" được tham khảo của tôi (điều chỉnh trong 30 phút theo đúng hướng ở mọi nơi). Các phạm vi ngắn hơn 30 phút được loại bỏ theo thứ tự tiên nghiệm - điều này có ý nghĩa vì những phạm vi đó không bao giờ có thể là một phần của khoảng thời gian 30 phút chồng chéo liên tục. Cũng làm cho truy vấn nhanh hơn.
Tính toán cho tất cả các ngày trong tháng 10 năm 2019 (phạm vi ví dụ):
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 tại đây
Lưu ý rằng LOCALTIMESTAMP
phụ thuộc vào múi giờ của phiên hiện tại. Cân nhắc sử dụng dấu thời gian trong bảng của bạn và CURRENT_TIMESTAMP
thay vì. Xem: