Нужно ли применять оконные функции для определения существующих пользователей
Что проверяют
Понимаете ли вы, когда оконная функция уместна, а когда достаточно группировки, и знаете ли порядок выполнения запроса. Ответ «да, оконные подходят» без разбора альтернатив обычно не засчитывают.
Как отвечать
Сначала уточнить определение: существующий это тот, у кого была активность до начала периода, новый это тот, у кого первое событие внутри периода. От формулировки зависит запрос, и на собеседовании вопрос часто ставят именно на это.
Окно уместно, когда нужно пометить каждую строку, не схлопывая их:
select user_id, event_date,
min(event_date) over (partition by user_id) as first_date
from eventsДальше first_date сравнивается с границей периода. Для той же задачи годятся row_number() по дате и lag(), если нужен разрыв между визитами.
Если на выходе нужен просто список или число, окно избыточно: group by user_id having min(event_date) < :start или not exists по истории отработают дешевле, потому что не тащат каждую строку через сортировку окна.
Где спотыкаются
Фильтруют период в where и считают первую дату уже по отфильтрованным строкам. Окно вычисляется после where, поэтому первой датой становится первая дата внутри периода, и все пользователи оказываются новыми. Историю либо не фильтруют, либо считают отдельным подзапросом.
Пытаются отфильтровать по самой оконной функции прямо в where. Так нельзя по той же причине: нужен подзапрос, общее табличное выражение или qualify там, где эта конструкция есть.
Путают рамку окна. Если указан order by, по умолчанию рамка это все строки от начала раздела до текущей, то есть накопительный итог, а без order by весь раздел целиком. Отсюда нарастающие числа там, где ждали общий итог. Ещё одна ловушка: count(*) в скользящем окне по датам считает события, а не уникальные дни, а count(distinct ...) внутри оконной функции не поддерживается.