TGViewer
Базы данных (Data Base) Базы данных (Data Base) @database_info · 8.04K subscribers
Post #361 1.41K
Задача. Подсчет сессий пользователя.

Не знаю почему на каждом 2 собеседовании любят давать эту задачу, в разных вариациях, тем не менее суть одна. Решений эта задача имеет также не мало, но мы попробуем решить ее через оконные функции, как мой самый любимый способ решения. Возьмем один из самых простых вариантов задачи, для каждого юзера мы имеем лог его данных который снимаем каждые 5 минут, если разница между двумя промежутками больше, то это новая сессия, нужно разметить каждую сессию.

+------+----------------------------+
| user | login |
+------+----------------------------+
| 1 | 2022-10-12 20:05:00.000000 |
| 1 | 2022-10-12 20:10:00.000000 |
| 1 | 2022-10-12 20:15:00.000000 |
| 1 | 2022-10-12 20:20:00.000000 |
| 1 | 2022-10-12 20:25:00.000000 |
| 1 | 2022-10-12 10:05:00.000000 |
| 1 | 2022-10-12 20:40:00.000000 |
| 1 | 2022-10-12 20:30:00.000000 |
| 1 | 2022-10-12 10:20:00.000000 |
| 1 | 2022-10-12 10:10:00.000000 |
| 1 | 2022-10-12 20:05:00.000000 |
| 2 | 2022-10-12 20:10:00.000000 |
| 2 | 2022-10-12 20:15:00.000000 |
| 2 | 2022-10-12 20:20:00.000000 |
| 2 | 2022-10-12 20:25:00.000000 |
| 2 | 2022-10-12 10:05:00.000000 |
| 2 | 2022-10-12 20:40:00.000000 |
| 2 | 2022-10-12 20:30:00.000000 |
| 2 | 2022-10-12 10:20:00.000000 |
| 2 | 2022-10-12 10:10:00.000000 |
+------+----------------------------+


Впервую очередь отсортируем данные и применим функцию lag для смещения данных на 1 значение вниз

SELECT t1.user,
login,
lag(login, 1, NULL) OVER
(PARTITION BY
t1.user ORDER BY t1.user,
login) next_log
FROM table t1

Теперь вычтем смещение и посмотрим разницу между 2 повторяющимися значениями, после чего применим функцию камулятивной суммы, это как раз таки и даст необходимый нам результат.

select *,
sum(ind) over
(PARTITION BY t3.user
ORDER BY t3.user rows
between unbounded preceding and current row) as sessions
from (
select t2.user,
login,
case
when (login-prev_log) > '5 mins' then 1
else 0
end ind
from (
SELECT t1.user,
login,
lag(login, 1,NULL)
OVER (PARTITION BY t1.user
ORDER BY t1.user, login) prev_log
FROM table t1) t2
) t3


#db

👉 @database_info
  • 👍 4
More from @database_info
  1. Oct 13, 2026🧱 Антипаттерн: Ненормализованная схема в SQL Когда нужно «быстро запилить фичу», руки тян…
  2. Oct 11, 2026🎯 Мини-гайд: как НЕ спроектировать монстра вместо схемы БД Когда проект только начинается…
  3. Oct 10, 2026🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.r…
  4. Oct 8, 2026Без каких навыков не обойтись в ИТ прямо сейчас? Разбираемся с одной из самых популярных С…
  5. Oct 8, 2026Антипаттерн: «Одна таблица на всё» Когда бизнес-логика усложняется, а структура БД остаётс…
  6. Oct 6, 2026❌ Антипаттерн: Хранить даты и время в VARCHAR Встречали такое? CREATE TABLE orders ( id SE…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →