Использовали ли вы оконные функции в базе данных
Что проверяют
Умеете ли вы решать аналитические задачи в самой базе, а не выгрузкой строк в Python и циклом. Следом обычно дают задачу: вывести последние три заказа каждого пользователя или посчитать разницу с предыдущим значением.
Как отвечать
Оконная функция считает значение по набору строк, связанных с текущей, но, в отличие от GROUP BY, не схлопывает их. Синтаксис: функция() OVER (PARTITION BY ... ORDER BY ... рамка). Основные группы:
- ранжирование:
ROW_NUMBER(),RANK(),DENSE_RANK(). На одинаковых значениях дают номера без повторов, с пропусками и без пропусков; - смещение:
LAG(),LEAD(),FIRST_VALUE(), удобно для разницы с прошлым периодом; - агрегаты с окном:
SUM() OVER (...)для нарастающего итога,AVG()с рамкойROWS BETWEEN 6 PRECEDING AND CURRENT ROWдля скользящего среднего за неделю.
Задача про заказы: в CTE посчитать ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn, во внешнем запросе оставить rn <= 3. Индекс по (user_id, created_at) избавляет базу от отдельной сортировки.
Покажите, как это выглядит в коде. В Django есть Window с RowNumber, Rank, Lag из django.db.models.functions, а с версии 4.2 по такой аннотации можно фильтровать, ORM сам обернёт запрос. В SQLAlchemy это func.row_number().over(partition_by=..., order_by=...). Если данные уже в pandas, аналоги groupby().rank(), cumsum(), shift().
Опыт подкрепите своим примером: какая была задача, сколько строк, во что превратился запрос. Если на работе не приходилось, так и скажите и решите задачу вслух.
Где спотыкаются
Пишут оконную функцию в WHERE. Она вычисляется после фильтрации, поэтому нужен подзапрос или CTE.
Не знают рамку по умолчанию. С ORDER BY окно идёт от начала раздела до текущей строки, и LAST_VALUE возвращает значение текущей строки, а не последней в разделе.
Путают ROW_NUMBER и RANK. При одинаковых датах ROW_NUMBER выберет строку произвольно, и «топ-3» будет меняться от запуска к запуску, если не добавить в сортировку уникальный столбец.