Если вы можете убедиться, что пара user_id
и timestamp
уникальна, вам может помочь следующее:
WITH cte AS
(
SELECT h1.user_id,
h1.page,
h1.timestamp,
coalesce(h1.timestamp - h2.timestamp <= INTERVAL '3600 SECONDS', false) shares_session_with_previous,
coalesce(h4.timestamp - h1.timestamp <= INTERVAL '3600 SECONDS', false) shares_session_with_next
FROM hit h1
LEFT JOIN hit h2
ON h2.user_id = h1.user_id
AND h2.timestamp = (SELECT max(h3.timestamp)
FROM hit h3
WHERE h3.user_id = h1.user_id
AND h3.timestamp < h1.timestamp)
LEFT JOIN hit h4
ON h4.user_id = h1.user_id
AND h4.timestamp = (SELECT min(h5.timestamp)
FROM hit h5
WHERE h5.user_id = h1.user_id
AND h5.timestamp > h1.timestamp)
)
SELECT c1.user_id,
c1.page,
c1.timestamp,
concat((SELECT concat(c2.user_id, '-', to_char(max(c2.timestamp), 'YYYYMMDDHH24MI'))
FROM cte c2
WHERE c2.user_id = c1.user_id
AND c2.timestamp <= c1.timestamp
AND NOT c2.shares_session_with_previous
GROUP BY c2.user_id),
(SELECT to_char(min(c2.timestamp), 'HH24MI')
FROM cte c2
WHERE c2.user_id = c1.user_id
AND c2.timestamp >= c1.timestamp
AND NOT c2.shares_session_with_next)) session_id
FROM cte c1
ORDER BY c1.timestamp;
Основной частью является CTE.Для каждой строки присоединяется строка с самой младшей более старой отметкой времени и строка с самой старой младшей отметкой времени.Интервал между старшей или самой младшей отметкой времени и отметкой времени строки проверяется, чтобы быть меньше или равным 3600 секундам.Результат этих проверок сохраняется в флагах shares_session_with_previous
и shares_session_with_next
.
. Затем флаги используются для получения начала и конца сеанса.Начало - это самая младшая временная метка, которая старше или равна текущей временной метке, где shares_session_with_previous
равно false
.Конец - это самая старая отметка времени, которая меньше или равна текущей отметке времени, где shares_session_with_next
равно false
.
Соответствующие значения начала и конца сеанса объединяются для получения идентификатора сеанса.
SQL Fiddle