ORDER BY и LIMIT в SQL — сортировка и ограничение результатов

Коротко

ORDER BY сортирует результат запроса по одному или нескольким столбцам. LIMIT ограничивает количество возвращаемых строк. Вместе они решают типичные задачи аналитика: найти топ-N, вытащить последние записи, сделать пагинацию.

ORDER BY — синтаксис

SELECT name, salary
FROM employees
ORDER BY salary DESC;

По умолчанию сортировка по возрастанию (ASC). Чтобы отсортировать по убыванию — добавляем DESC.

Сортировка по нескольким столбцам

Можно указать несколько столбцов через запятую. SQL сначала сортирует по первому, а при одинаковых значениях — по второму:

SELECT department, name, salary
FROM employees
ORDER BY department ASC, salary DESC;

Сотрудники сгруппируются по отделам в алфавитном порядке, внутри каждого отдела — по убыванию зарплаты.

Сортировка по номеру столбца

Вместо имени столбца можно указать его порядковый номер в SELECT:

SELECT name, salary
FROM employees
ORDER BY 2 DESC;

Здесь 2 — это salary. Удобно для быстрых запросов, но в продакшн-коде лучше писать имена явно — так читаемее.

ORDER BY с выражениями

Сортировать можно не только по столбцам, но и по выражениям:

SELECT name, salary, bonus
FROM employees
ORDER BY salary + bonus DESC;

NULL в сортировке

При сортировке NULL-значения по умолчанию попадают в конец (PostgreSQL при ASC) или в начало — зависит от СУБД. Чтобы управлять этим явно, используйте NULLS FIRST / NULLS LAST:

SELECT name, manager_id
FROM employees
ORDER BY manager_id ASC NULLS LAST;

Это работает в PostgreSQL и Oracle. В MySQL такого синтаксиса нет — придётся использовать трюк:

-- MySQL: NULL в конец при ASC
ORDER BY manager_id IS NULL, manager_id ASC;

LIMIT — ограничение результата

LIMIT задаёт максимальное количество строк в результате:

SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 10;

Вернёт 10 самых высокооплачиваемых сотрудников.

Разница между СУБД

Синтаксис СУБД
LIMIT 10 PostgreSQL, MySQL, SQLite, ClickHouse
TOP 10 (после SELECT) SQL Server
FETCH FIRST 10 ROWS ONLY Стандарт SQL, PostgreSQL, Oracle 12c+
-- SQL Server
SELECT TOP 10 name, salary
FROM employees
ORDER BY salary DESC;

-- Стандартный SQL (ANSI)
SELECT name, salary
FROM employees
ORDER BY salary DESC
FETCH FIRST 10 ROWS ONLY;

На собеседовании обычно ожидают PostgreSQL-синтаксис с LIMIT, но знать альтернативы полезно.

OFFSET — пропуск строк

OFFSET пропускает первые N строк. Используется для пагинации:

SELECT name, created_at
FROM orders
ORDER BY created_at DESC
LIMIT 20 OFFSET 40;

Этот запрос пропустит первые 40 строк и вернёт строки 41–60. Это третья «страница» по 20 записей.

Проблема производительности OFFSET

OFFSET работает наивно: СУБД читает и отбрасывает все пропущенные строки. При OFFSET 1000000 база прочитает миллион строк впустую. Для больших таблиц лучше использовать keyset pagination (курсорная пагинация):

-- Вместо OFFSET
SELECT id, name, created_at
FROM orders
WHERE created_at < '2025-12-01'
ORDER BY created_at DESC
LIMIT 20;

Фильтруем по последнему значению с предыдущей страницы — это работает через индекс и не замедляется на больших смещениях.

Практические примеры

Топ-5 клиентов по выручке

SELECT customer_id, SUM(amount) AS total
FROM orders
GROUP BY customer_id
ORDER BY total DESC
LIMIT 5;

Последние 10 заказов

SELECT order_id, customer_id, created_at
FROM orders
ORDER BY created_at DESC
LIMIT 10;

Второй по величине элемент

Классическая задача с собеседования — найти вторую по величине зарплату:

SELECT DISTINCT salary
FROM employees
ORDER BY salary DESC
LIMIT 1 OFFSET 1;

Типичные ошибки

ORDER BY в подзапросе. В PostgreSQL сортировка в подзапросе игнорируется, если внешний запрос не гарантирует порядок. Результат подзапроса — это множество, а у множеств нет порядка:

-- Порядок не гарантирован
SELECT * FROM (
  SELECT name, salary FROM employees ORDER BY salary DESC
) sub
LIMIT 5;

Правильно — ставить ORDER BY во внешнем запросе.

LIMIT без ORDER BY. Без сортировки LIMIT вернёт произвольные строки. Результат будет непредсказуемым и может меняться между запусками.

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

«Что вернёт LIMIT без ORDER BY?» — Произвольные строки. Порядок не определён стандартом SQL, и СУБД может вернуть строки в любом порядке.

«Как найти N-ю по величине зарплату?» — ORDER BY salary DESC, затем LIMIT 1 OFFSET N-1. Либо через оконную функцию DENSE_RANK().

«Чем LIMIT отличается от FETCH FIRST?» — LIMIT — расширение PostgreSQL/MySQL. FETCH FIRST — стандарт ANSI SQL. Логика одинаковая, синтаксис разный.

«Как обрабатываются NULL при ORDER BY?» — Зависит от СУБД. В PostgreSQL при ASC NULL идут в конец, при DESC — в начало. Управлять можно через NULLS FIRST / NULLS LAST.

«Почему OFFSET медленный на больших значениях?» — Потому что СУБД физически читает и отбрасывает все пропущенные строки. Для эффективной пагинации используют keyset pagination — фильтрацию по последнему значению предыдущей страницы.

Потренируйтесь писать запросы с ORDER BY и LIMIT — откройте тренажёр с 1500+ вопросами по SQL. Больше теории — в гайде SQL для начинающих, больше задач — на странице с примерами вопросов.

FAQ

Можно ли сортировать по столбцу, которого нет в SELECT?

Да. ORDER BY может ссылаться на любой столбец таблицы, даже если он не указан в SELECT. Исключение — запросы с DISTINCT: сортировать можно только по выбранным столбцам.

Работает ли ORDER BY с алиасами?

Да, в большинстве СУБД. ORDER BY выполняется после SELECT, поэтому видит алиасы. Но в WHERE алиасы использовать нельзя — он выполняется раньше.

Что будет, если LIMIT больше, чем строк в таблице?

SQL вернёт все имеющиеся строки без ошибки. LIMIT — это верхняя граница, а не точное количество.

Можно ли использовать LIMIT без OFFSET?

Да, и в большинстве случаев так и делают. OFFSET нужен только для пагинации. Для задач вроде «топ-10» достаточно одного LIMIT.