PARTITION BY разбивает строки на независимые группы, внутри которых ROW_NUMBER начинает нумерацию с 1. ORDER BY в OVER определяет последовательность номеров, но не порядок вывода результата. При равных значениях сортировки нужен уникальный дополнительный ключ, если требуется воспроизводимый результат.
Как работает PARTITION BY в ROW_NUMBER() OVER (...)?
Нумерация строк отдельно в каждой группе: пример с заказами, детерминированный порядок и отличие от GROUP BY.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
PARTITION BY задаёт группы для оконного вычисления, не схлопывая строки. Например, пронумеруем заказы каждого клиента от нового к старому:
SELECT customer_id, id, created_at,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY created_at DESC, id DESC
) AS rn
FROM orders
ORDER BY customer_id, rn;
Для клиента A с тремя заказами будут номера 1, 2, 3; для клиента B с двумя — снова 1, 2. В примере предполагается, что id уникален, а created_at заполнен. Второй ключ устраняет неопределённость между заказами с одинаковой датой.
Если убрать PARTITION BY, все строки образуют одну группу и получают сквозные номера. Если заменить оконное вычисление обычным GROUP BY customer_id, получится другой результат: агрегирование по клиентам, а не номер каждого заказа.
Чтобы получить последний заказ каждого клиента, вычисляют номер во вложенном запросе:
WITH numbered AS (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY created_at DESC, id DESC
) AS rn
FROM orders
)
SELECT customer_id, id, created_at
FROM numbered
WHERE rn = 1;
В PostgreSQL фильтровать оконный результат в WHERE того же уровня нельзя. Внешний ORDER BY нужен отдельно, если требуется порядок отображения. ROW_NUMBER выдаёт разные номера даже при равных значениях: для одинакового ранга используют RANK или DENSE_RANK.