SQL: Вывести третью страницу для каждого пользователя
Условие
У вас есть табличка log, в которой присутствуют колонки user_id, time, page.
Для каждого user_id нужно вывести третью страницу (page) в хронологическом порядке.
Структура таблицы log:
- user_id (integer) - идентификатор пользователя
- time (timestamp) - время посещения
- page (varchar) - название страницы
Ожидаемый результат:
Таблица с колонками user_id и page, где page - это третья посещённая страница данным пользователем.
Источник: реальное собеседование на продуктового аналитика
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Описание подхода
Для решения этой задачи используем оконные функции (window functions) в SQL. Ключевая идея: присвоить каждой странице пользователя номер в хронологическом порядке и отфильтровать только те строки, где номер равен 3.
SQL-запрос
WITH ranked_pages AS (
SELECT
user_id,
page,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY time ASC) as page_number
FROM log
)
SELECT user_id, page
FROM ranked_pages
WHERE page_number = 3
Почему этот подход работает
ROW_NUMBER() — оконная функция, которая нумерует строки в порядке, определённом в ORDER BY:
PARTITION BY user_id— нумерация независима для каждого пользователяORDER BY time ASC— нумерация в хронологическом порядке (от старых событий к новым)WHERE page_number = 3— берём только третьи строки
Альтернативный синтаксис (без CTE)
Если СУБД позволяет использовать WHERE на результаты window-функций:
SELECT user_id, page
FROM (
SELECT
user_id,
page,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY time ASC) as page_number
FROM log
) subquery
WHERE page_number = 3
Важные моменты
- ROW_NUMBER vs RANK: если есть равные timestamps, ROW_NUMBER всё равно присвоит разные номера (по внутреннему порядку), а RANK — одинаковые
- Обработка NULL: если есть пользователи с менее чем 3 страницами, они не появятся в результате (это ожидаемо)
- Производительность: для больших таблиц может потребоваться индекс на (user_id, time)
Пример данных
Дано:
| user_id | time | page |
|---|---|---|
| 1 | 2024-01-01 10:00 | home |
| 1 | 2024-01-01 10:05 | profile |
| 1 | 2024-01-01 10:10 | settings |
| 1 | 2024-01-01 10:15 | logout |
| 2 | 2024-01-01 11:00 | home |
| 2 | 2024-01-01 11:05 | search |
| 2 | 2024-01-01 11:10 | details |
Результат:
| user_id | page |
|---|---|
| 1 | settings |
| 2 | details |
Это стандартная задача на собеседованиях для проверки понимания оконных функций.
Похожие вопросы
- SQL: Посчитать воронку конверсии
- SQL: Найти товары, которые покупали вместе
- SQL: Скользящее среднее за 7 дней
- SQL: Посчитать DAU и WAU
- SQL: Анализ повторных покупок
- SQL: Year-over-Year сравнение выручки
- SQL: Найти товары с падением продаж
- SQL: Расчет конверсии по шагам регистрации
- SQL: Расчет времени до первой покупки
- Продуктовый кейс: Запуск новой страны
- SQL: Найти первую и последнюю покупку каждого клиента
- SQL: Найти пользователей с регулярными платежами
- SQL: Процентиль выручки по клиентам
- SQL: Cumulative sum (нарастающий итог)
- SQL: Расчет LTV по когортам
- SQL: Расчет ARPU по источникам трафика
- SQL: Определить время между событиями (LAG/LEAD)
- Вероятность: игра с тремя дверями
- SQL: Найти пользователей без активности более 30 дней
- SQL: Найти VIP клиентов по правилу Парето