Функция ROW_NUMBER() в SQL: синтаксис, примеры, разбор

ROW_NUMBER() — оконная функция, которая присваивает каждой строке уникальный порядковый номер (1, 2, 3, …) внутри окна, заданного PARTITION BY, в порядке ORDER BY. В отличие от RANK и DENSE_RANK, при одинаковых значениях номера не повторяются. Главные применения у аналитика — «топ-N в группе» и дедупликация строк.

Синтаксис

ROW_NUMBER() OVER (PARTITION BY колонки ORDER BY колонки)

Примеры использования

Пример 1: Топ-1 заказ по сумме для каждого клиента

SELECT user_id, order_id, amount
FROM (
  SELECT user_id, order_id, amount,
         ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rn
  FROM orders
) t
WHERE rn = 1;

Результат:

user_id | order_id | amount
1       | 105      | 4200
2       | 210      | 3100

Пример 2: Дедупликация: оставить самую свежую запись по email

WITH ranked AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY email ORDER BY updated_at DESC) AS rn
  FROM users
)
SELECT * FROM ranked WHERE rn = 1;

Результат:

email          | updated_at
a@mail.ru      | 2026-03-01
b@mail.ru      | 2026-02-14
Порешать SQL-задачи в тренажёре →

Типичная ошибка

ROW_NUMBER() нельзя использовать прямо в WHERE — окна вычисляются после WHERE и GROUP BY. Оберни запрос в подзапрос или CTE и фильтруй по псевдостолбцу снаружи (rn = 1). Ещё частая ошибка — забыть PARTITION BY: тогда нумерация идёт по всей таблице, а не по группам.

Где спрашивают на собеседовании

ROW_NUMBER() — один из самых частых вопросов на собеседовании аналитика. Спрашивают «как достать топ-N по каждой категории» и «как удалить дубли, оставив одну строку». Умей проговорить разницу с RANK/DENSE_RANK и почему фильтр идёт через подзапрос.

FAQ: частые вопросы про ROW_NUMBER

Чем ROW_NUMBER отличается от RANK и DENSE_RANK?

ROW_NUMBER даёт уникальные номера (1,2,3,4) даже при равных значениях. RANK при равенстве выдаёт одинаковый ранг и пропускает следующий (1,1,3). DENSE_RANK — одинаковый ранг без пропусков (1,1,2).

Можно ли использовать ROW_NUMBER без ORDER BY?

Формально да, но порядок номеров станет недетерминированным — движок пронумерует строки как ему удобно. Для воспроизводимого результата ORDER BY внутри OVER практически обязателен.

Как получить топ-3 в каждой группе через ROW_NUMBER?

Нумеруй строки с PARTITION BY по группе и ORDER BY по нужному критерию, затем во внешнем запросе оставь rn <= 3.

Задачи в тренажёре по теме

Вопросы с собеседований по теме

Смежные темы SQL

Оконные функции · Ранжирование · Дедупликация

Другие функции SQL

RANK · DENSE_RANK · LAG · LEAD · NTILE · SUM OVER

Открыть SQL-тренажёр (565 задач) →