0Pricing
Coding Interview Prep · Урок

Обработка совпадений среди первых N строк

Узнайте, когда использовать RANK или DENSE_RANK, чтобы включить все строки с одинаковыми значениями.

«Обработка совпадений среди первых N строк» — бесплатный урок Coding Interview Prep на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Coding Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Coding Interview Prep содержит 4 уроков всего.

Дополнительный вопрос о ничьей

После того как Вы уверенно решаете задачи top-N с помощью ROW_NUMBER, интервьюер усложняет вопрос: «Что, если на границе окажутся два сотрудника с абсолютно одинаковой зарплатой? Следует ли включить обоих?»

Это отличает кандидатов, заучивших один запрос, от тех, кто понимает семантику ранжирования. Ответ зависит от выбора между ROW_NUMBER, RANK и DENSE_RANK. В этом уроке показано, какой функции соответствует каждый вариант бизнес-требования.

ROW_NUMBER скрывает ничьи

ROW_NUMBER присваивает каждой строке строго уникальное целое число. Даже если значения в столбце сортировки совпадают, одна строка получит 2, а другая — 3 в произвольном порядке.

Следствие: фильтр WHERE rn <= 3 возвращает ровно 3 строки и может незаметно исключить строку с таким же значением, которую, возможно, следовало включить. Это подходит, когда действительно требуется фиксированное количество строк, но неверно, когда должны пройти все строки с одинаковыми значениями.

-- Salaries: 100, 90, 90, 80
-- ROW_NUMBER -> 1, 2, 3, 4  (the two 90s get 2 and 3 arbitrarily)
ROW_NUMBER() OVER (ORDER BY salary DESC)

RANK оставляет пропуски

RANK присваивает строкам с одинаковыми значениями одинаковый ранг, а затем пропускает следующие значения, учитывая ничьи. Две строки, занявшие 2-е место, обе получают 2, а следующая строка получает ранг 4, а не 3.

Используйте RANK, когда нужны «топ-3 позиции» и одну позицию могут занимать несколько человек, как в настоящих турнирных таблицах, где два серебряных призёра означают отсутствие бронзового.

-- Salaries: 100, 90, 90, 80
-- RANK -> 1, 2, 2, 4   (rank 3 is skipped)
RANK() OVER (ORDER BY salary DESC)

DENSE_RANK не оставляет пропусков

DENSE_RANK также присваивает строкам с одинаковыми значениями одинаковый ранг, но после этого не пропускает значения. Две строки с рангом 2 обе получают 2, а следующее отличающееся значение получает 3.

Используйте DENSE_RANK, когда вопрос касается различающихся значений: «трёх самых высоких различных уровней зарплаты» или «трёх лучших ценовых категорий». Эта функция считает уникальные значения, а не строки.

-- Salaries: 100, 90, 90, 80
-- DENSE_RANK -> 1, 2, 2, 3   (no gap)
DENSE_RANK() OVER (ORDER BY salary DESC)

Сравнение бок о бок

Для списка зарплат 100, 90, 90, 80 три функции дают такие результаты:

  • ROW_NUMBER: 1, 2, 3, 4
  • RANK: 1, 2, 2, 4
  • DENSE_RANK: 1, 2, 2, 3

Эту таблицу стоит выучить наизусть. Интервьюер может просто попросить заполнить её для заданного списка, и именно правильное понимание пропусков является главным.

SELECT salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn,
  RANK()       OVER (ORDER BY salary DESC) AS rnk,
  DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
FROM employees;

Включение всех строк с одинаковым рангом с помощью RANK

Чтобы ответить на вопрос «топ-3, но включить всех, кто разделяет граничное место», используйте фильтр RANK() <= 3. Если два человека занимают 3-е место, появятся оба, поэтому результат может содержать более 3 строк.

Именно это подразумевается в формулировке «топ-3 позиции», а не «любые 3 строки». Явно укажите, что при наличии одинаковых значений количество строк может превышать N.

WITH ranked AS (
  SELECT name, department, salary,
         RANK() OVER (
           PARTITION BY department ORDER BY salary DESC
         ) AS rnk
  FROM employees
)
SELECT name, department, salary, rnk
FROM ranked
WHERE rnk <= 3
ORDER BY department, rnk;

Три лучших различных уровня с помощью DENSE_RANK

Если требуется получить «три лучших различных уровня зарплаты» и включить всех сотрудников на этих трёх уровнях, используйте DENSE_RANK() <= 3.

В результате может оказаться много строк: все сотрудники из трёх самых высоких уровней оплаты, сколько бы их ни было на каждом уровне. Главное понять, что DENSE_RANK считает различные значения, поэтому фильтр выбирает уровни значений, а не фиксированное количество строк.

WITH ranked AS (
  SELECT name, salary,
         DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
  FROM employees
)
SELECT name, salary, drnk
FROM ranked
WHERE drnk <= 3
ORDER BY drnk;

Как выбрать функцию

Соотнесите формулировку с функцией:

  • «Ровно N строк» или постраничная выдача → ROW_NUMBER (добавьте критерий разрешения ничьей).
  • «Топ-N позиций, одинаковые значения занимают одну позицию» → RANK.
  • «Топ-N различных значений / уровней / категорий» → DENSE_RANK.

Если требования неоднозначны, спросите: «Если на границе возникнет ничья, следует ли включить все строки с одинаковым значением или ограничить результат N строками?» Такой уточняющий вопрос сам по себе принесёт дополнительные баллы.

Критерии разрешения ничьей всё ещё важны

Даже при использовании RANK или DENSE_RANK добавление вторичного ключа в ORDER BY управляет порядком отображения строк с одинаковыми значениями и сохраняет стабильность вывода. Оно не меняет состав строк, попадающих в результат, но делает результаты воспроизводимыми.

При использовании ROW_NUMBER этот критерий необходим, потому что именно он определяет, какая строка с одинаковым значением вообще останется после отсечения по rn.

RANK() OVER (
  PARTITION BY department
  ORDER BY salary DESC, name ASC
) AS rnk

Разобранный пример: лидеры по очкам

В таблице game_scores есть столбцы player и score. Интервьюер хочет получить «всех игроков, занявших первые 2 места по очкам». Если два игрока делят первое место, оба получают позицию 1, а следующий отличный результат — позицию 2.

«Позиции» без пропусков после ничьей указывают на DENSE_RANK. Если бы вместо этого было сказано «топ-2 места с пропусками», следовало бы выбрать RANK. Внимательно слушайте точную формулировку.

WITH r AS (
  SELECT player, score,
         DENSE_RANK() OVER (ORDER BY score DESC) AS pos
  FROM game_scores
)
SELECT player, score, pos
FROM r
WHERE pos <= 2
ORDER BY pos, player;

Распространённые ошибки

Ошибки, на которые обращают внимание интервьюеры:

  • Использование ROW_NUMBER, когда задача требует включить строки с одинаковыми значениями, из-за чего подходящая строка незаметно исключается.
  • Непонимание различий в поведении пропусков у RANK и DENSE_RANK.
  • Забыть, что фильтры RANK/DENSE_RANK могут вернуть более N строк, а затем объявить результат неверным.
  • Пропуск PARTITION BY, когда top-N нужно вычислять для каждой группы, из-за чего вместо этого ранжируется вся таблица.

Быстрая проверка

Выберите подходящую функцию ранжирования для описанного поведения при совпадающих значениях.

Итоги: обработка совпадающих значений

Три функции — три варианта обработки одинаковых значений:

  • ROW_NUMBER: всегда уникальные номера, ровно N строк, порядок среди совпадений определяется произвольно.
  • RANK: одинаковые значения получают один ранг, после них появляются пропуски.
  • DENSE_RANK: одинаковые значения получают один ранг, пропусков нет, подсчитываются различные значения.

Выбирайте функцию согласно формулировке вопроса, задавайте уточняющий вопрос, если она неоднозначна, и помните: фильтры по RANK/DENSE_RANK могут по замыслу возвращать больше N строк.

Часто задаваемые вопросы

Урок «Обработка совпадений среди первых N строк» бесплатный?

Да — полный текст урока «Обработка совпадений среди первых N строк» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Coding Interview Prep, подпишись на CoddyKit PRO. Курс Coding Interview Prep содержит 4 уроков всего.

Чему я научусь в уроке «Обработка совпадений среди первых N строк»?

Узнайте, когда использовать RANK или DENSE_RANK, чтобы включить все строки с одинаковыми значениями. Ты практикуешь Coding Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Coding Interview Prep?

Предыдущий опыт не требуется. Coding Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Обработка совпадений среди первых N строк»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Coding Interview Prep?

Да. Каждый урок Coding Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Первые N строк в каждой группе с ROW_NUMBER
  2. Обработка совпадений среди первых N строк
  3. Безопасное удаление дубликатов строк
  4. Сохранение последней строки для каждого ключа
← Назад к Coding Interview Prep