Надёжное получение первых N строк
Узнайте, почему ORDER BY вместе с LIMIT может давать недетерминированный результат без дополнительного критерия сортировки.
«Надёжное получение первых N строк» — бесплатный урок SQL Interview Prep на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Interview Prep содержит 4 уроков всего.
Скрытая ошибка в запросах для N лучших
Запрос «Покажите пять сотрудников с самой высокой зарплатой» кажется простым: ORDER BY salary DESC LIMIT 5. Но интервьюеры специально оставляют здесь подвох. Что, если на границе шесть человек получают одинаковую зарплату? Что, если одинаковые значения встречаются во множестве строк?
Главная проблема — детерминированность: если значения ключа сортировки совпадают, LIMIT произвольно обрезает результат, и точный набор возвращённых строк может меняться между запусками. Этот урок поможет сделать запросы для N лучших надёжными.
Почему ORDER BY + LIMIT может давать недетерминированный результат
Рассмотрим зарплаты, при которых строки с рангами 4, 5 и 6 имеют значение 50000. ORDER BY salary DESC LIMIT 5 должен вернуть ровно 5 строк, поэтому он оставляет две из трёх совпадающих строк и исключает одну, но неизвестно, какие именно две.
При повторном запуске запроса или после того, как оптимизатор изменит планы выполнения, Вы можете получить других людей. Именно эту недетерминированность интервьюеры хотят, чтобы Вы заметили.
SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 5;Исправление 1: добавьте уникальный дополнительный ключ
Самое простое исправление — сделать порядок сортировки полным, добавив столбец с уникальными значениями, обычно первичный ключ. Теперь никакие две строки не совпадают по полному ключу, поэтому граница отбора становится детерминированной и воспроизводимой.
Это не меняет набор отображаемых значений зарплаты, но делает выбор среди строк с одинаковой зарплатой стабильным между запусками.
SELECT id, name, salary
FROM employees
ORDER BY salary DESC, id ASC
LIMIT 5;Исправление 2: включите все совпадения с помощью WITH TIES
Иногда требуется «включить всех, у кого значение совпадает с граничным», а не вернуть ровно N строк. Стандартный SQL и SQL Server поддерживают WITH TIES, который возвращает дополнительные строки, совпадающие со значением ORDER BY последней строки.
Если зарплату, занимающую 5-е место, получают три человека, запрос вернёт 7 строк. Обратите внимание: WITH TIES требует наличия ORDER BY.
SELECT name, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 5 ROWS WITH TIES;Сначала уточните требование
Перед написанием кода спросите интервьюера: «Если на границе есть совпадения, нужно вернуть ровно N строк или все строки с одинаковым значением?» Один такой уточняющий вопрос показывает Ваш опыт.
- Ровно N строк, стабильный результат: добавьте уникальный дополнительный ключ.
- Включить все совпадения: используйте
WITH TIESилиRANK. - Различные значения: используйте
DENSE_RANK.
Переносимый подход с оконной функцией
Во многих СУБД нет WITH TIES. Переносимый и мощный шаблон использует оконную функцию ранжирования во вложенном запросе или CTE, а затем отбирает строки по рангу. ROW_NUMBER возвращает ровно N строк с детерминированным ключом сортировки.
Оконную функцию необходимо поместить во вложенный запрос, поскольку напрямую обратиться к ней в WHERE нельзя.
SELECT name, salary
FROM (
SELECT name, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC, id ASC) AS rn
FROM employees
) ranked
WHERE rn <= 5;RANK для сохранения совпадений
Замените ROW_NUMBER на RANK, если нужно сохранить все совпадающие строки и оставить пропуски в нумерации. Если три строки делят 4-е место, всем присваивается ранг 4, а следующий ранг равен 7.
Фильтрация по условию rank <= 5 вернёт все строки из пяти лучших позиций по зарплате, включая совпадения.
SELECT name, salary
FROM (
SELECT name, salary,
RANK() OVER (ORDER BY salary DESC) AS rnk
FROM employees
) ranked
WHERE rnk <= 5;DENSE_RANK для N лучших различных значений
«3 лучших уровня зарплаты» (а не 3 лучших человека) означает различные значения. DENSE_RANK присваивает совпадающим значениям один и тот же ранг и не пропускает номера, поэтому условие dense_rnk <= 3 вернёт всех, кто получает одну из трёх самых высоких различных зарплат.
Умение определить, какая функция ранжирования соответствует формулировке, — классический способ отличить сильного кандидата.
SELECT name, salary
FROM (
SELECT name, salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
FROM employees
) ranked
WHERE drnk <= 3;Особый случай для первого места
Для одной строки на первом месте конструкция ORDER BY ... LIMIT 1 работает, но всё ещё может неоднозначно обрабатывать совпадения. Если нужно получить все строки с максимальным значением, сравните их с максимумом из вложенного запроса или используйте RANK() = 1.
Вариант с подзапросом максимума прост и работает в любом диалекте.
SELECT name, salary
FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);Сравнение подходов
Кратко о выборе каждого инструмента для надёжного получения N лучших строк:
LIMIT+ уникальный дополнительный ключ: ровно N строк, стабильный результат, самый простой вариант.FETCH ... WITH TIES: ровно N строк плюс совпадения на границе, стандартный SQL.ROW_NUMBER: ровно N строк, детерминированный результат, полностью переносимый подход.RANK: N лучших позиций, включая все совпадения.DENSE_RANK: N лучших различных значений.
Предпросмотр N лучших в каждой группе
Подход с оконной функцией прекрасно обобщается. Добавьте PARTITION BY, чтобы получить N лучших строк внутри каждой группы, например двух сотрудников с самой высокой зарплатой в каждом отделе. После разбиения на группы применяется тот же фильтр rn <= n.
Получение N лучших строк в каждой группе — одна из наиболее часто встречающихся задач на собеседованиях, решаемая с помощью только что изученного шаблона.
SELECT department, name, salary
FROM (
SELECT department, name, salary,
ROW_NUMBER() OVER (PARTITION BY department
ORDER BY salary DESC, id ASC) AS rn
FROM employees
) ranked
WHERE rn <= 2;Быстрая проверка
Сопоставьте требование с правильной функцией.
Итоги
Чтобы надёжно вернуть N лучших строк:
- Один только
ORDER BY ... LIMITдаёт недетерминированный результат, если значения ключа сортировки совпадают. - Добавьте уникальный дополнительный ключ для стабильного результата ровно с N строками.
- Используйте
WITH TIESилиRANK, чтобы сохранить совпадения на границе. - Используйте
DENSE_RANKдля N лучших различных значений. - Всегда уточняйте, нужно ли интервьюеру вернуть ровно N строк или все совпадающие строки.
Часто задаваемые вопросы
Урок «Надёжное получение первых N строк» бесплатный?
Да — полный текст урока «Надёжное получение первых N строк» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Interview Prep, подпишись на CoddyKit PRO. Курс SQL Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «Надёжное получение первых N строк»?
Узнайте, почему ORDER BY вместе с LIMIT может давать недетерминированный результат без дополнительного критерия сортировки. Ты практикуешь SQL Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать SQL Interview Prep?
Предыдущий опыт не требуется. SQL Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Надёжное получение первых N строк»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке SQL Interview Prep?
Да. Каждый урок SQL Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Сортировка по нескольким столбцам и размещение NULL
- LIMIT, OFFSET и FETCH FIRST
- Надёжное получение первых N строк
- Сортировка по выражениям и псевдонимам