SQLORDER BYtutorialbeginner

Что такое ORDER BY в SQL?

ORDER BY — команда для сортировки результата в SQL. Простыми словами: ASC и DESC, сортировка по нескольким колонкам, NULL-ы в сортировке, комбо с LIMIT для топ-N. Куча примеров и три задачи на потренироваться.

13 мин чтенияСправочникSQL · ORDER BY · tutorial · beginner

ORDER BY — это часть SQL-запроса, которая отвечает за сортировку результата.

Когда ты пишешь запрос без ORDER BY, база данных не обязана возвращать строки в каком-то понятном порядке. Сегодня они могут прийти так, завтра иначе, после добавления индекса — вообще по-другому. Для базы это нормально: она выбирает удобный для себя способ достать данные. Но для человека такой результат выглядит как хаос.

ORDER BY решает эту проблему. С его помощью ты явно говоришь базе:

Отсортируй результат вот по этой колонке: от меньшего к большему или от большего к меньшему.

Представь стопку книг, которую высыпали на стол как попало. Если попросить разложить книги по названию, это будет похоже на ORDER BY title. Если попросить сначала положить самые новые книги, это уже ORDER BY year DESC.

Зачем нужен ORDER BY

Сортировка нужна почти в любом реальном приложении.

Без неё неудобно смотреть списки, строить рейтинги, выводить историю действий, показывать товары, новости, заказы и отчёты.

Типичные ситуации:

  • показать товары от дешёвых к дорогим;
  • вывести последние новости сверху;
  • собрать топ пользователей по очкам;
  • отсортировать города по алфавиту;
  • показать заказы от новых к старым;
  • найти самые крупные платежи;
  • построить лидерборд.

Например, запрос без сортировки:

SELECT id, title, price
FROM products;

Может вернуть товары в любом порядке. Не потому что база ошиблась, а потому что ты не сказал ей, какой порядок нужен.

А вот так уже понятно:

SELECT id, title, price
FROM products
ORDER BY price;

Теперь товары будут отсортированы по цене от меньшей к большей.

Базовый синтаксис ORDER BY

Общий вид такой:

SELECT column1, column2
FROM table_name
ORDER BY column_name ASC;

Или так:

SELECT column1, column2
FROM table_name
ORDER BY column_name DESC;

Есть два направления сортировки:

  • ASC — по возрастанию;
  • DESC — по убыванию.

ASC используется по умолчанию. Поэтому эти два запроса означают одно и то же:

SELECT title, price
FROM products
ORDER BY price ASC;
SELECT title, price
FROM products
ORDER BY price;

Оба запроса отсортируют товары от самой маленькой цены к самой большой.

А если нужно наоборот — от дорогих к дешёвым, используй DESC:

SELECT title, price
FROM products
ORDER BY price DESC;

Пример с книгами

Допустим, есть таблица books:

id title author year rating
1 War and Peace Leo Tolstoy 1869 4.8
2 The Master and Margarita Mikhail Bulgakov 1967 4.9
3 And Quiet Flows the Don Mikhail Sholokhov 1940 4.7
4 Crime and Punishment Fyodor Dostoevsky 1866 4.8

Отсортируем книги по году издания от старых к новым:

SELECT title, year
FROM books
ORDER BY year;

Результат:

title year
Crime and Punishment 1866
War and Peace 1869
And Quiet Flows the Don 1940
The Master and Margarita 1967

Поскольку мы не написали DESC, база использовала ASC — сортировку по возрастанию.

Теперь сделаем наоборот: сначала новые книги, потом старые.

SELECT title, year
FROM books
ORDER BY year DESC;

Результат:

title year
The Master and Margarita 1967
And Quiet Flows the Don 1940
War and Peace 1869
Crime and Punishment 1866

DESC перевернул порядок.

ASC и DESC на разных типах данных

ORDER BY работает не только с числами.

Числа сортируются по величине:

SELECT title, price
FROM products
ORDER BY price;

Даты сортируются по времени:

SELECT title, created_at
FROM posts
ORDER BY created_at DESC;

Строки сортируются по алфавиту:

SELECT name
FROM users
ORDER BY name;

Для новичка важно запомнить простую логику:

Тип данных ASC DESC
Числа от меньшего к большему от большего к меньшему
Даты от старых к новым от новых к старым
Строки по алфавиту в обратном алфавитном порядке

В интерфейсах часто используют именно DESC по дате, потому что пользователю обычно интересны свежие записи.

Например:

SELECT title, published_at
FROM articles
ORDER BY published_at DESC;

Так мы получим сначала последние статьи, а потом более старые.

ORDER BY по нескольким колонкам

Иногда одной колонки для сортировки недостаточно.

Например, мы хотим отсортировать сотрудников сначала по отделу, а внутри каждого отдела — по зарплате от большей к меньшей.

Для этого в ORDER BY можно перечислить несколько колонок через запятую:

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

База будет сортировать так:

  1. Сначала по department ASC.
  2. Если отдел одинаковый — внутри отдела по salary DESC.
  3. Если и зарплата одинаковая — порядок между такими строками всё ещё может быть произвольным.

Допустим, есть таблица employees:

id name department salary
1 Anna IT 120000
2 Boris Sales 80000
3 Vera IT 150000
4 Gregory HR 70000
5 Denis IT 120000
6 Elena Sales 95000

Запрос:

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

Результат:

name department salary
Gregory HR 70000
Vera IT 150000
Anna IT 120000
Denis IT 120000
Elena Sales 95000
Boris Sales 80000

Сначала идут отделы по алфавиту: HR, IT, Sales. А внутри каждого отдела сотрудники отсортированы по зарплате от большей к меньшей.

Но обрати внимание: у Anna и Denis одинаковый отдел и одинаковая зарплата. Значит, между ними порядок не гарантирован. Сегодня Anna может быть выше Denis, завтра наоборот.

Если нужен стабильный и предсказуемый порядок, добавь ещё одну колонку:

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

Теперь при одинаковой зарплате сотрудники будут отсортированы по имени.

Почему важна стабильная сортировка

В учебных примерах часто кажется: «Ну какая разница, в каком порядке идут две одинаковые строки?»

В реальных задачах разница есть.

Представь страницу с заказами. На первой странице пользователь видит 20 заказов. Потом нажимает «следующая страница». Если сортировка нестабильная, некоторые заказы могут повториться, а некоторые — пропасть между страницами.

Особенно это важно при связке ORDER BY и LIMIT.

Плохо:

SELECT id, customer_id, created_at
FROM orders
ORDER BY created_at DESC
LIMIT 20;

Если у нескольких заказов одинаковый created_at, база может менять их внутренний порядок.

Надёжнее:

SELECT id, customer_id, created_at
FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 20;

Здесь id добавлен как дополнительный критерий. Он делает порядок детерминированным: если даты одинаковые, выше будет заказ с большим id.

Хорошая привычка: если сортируешь по колонке, где могут быть одинаковые значения, добавляй уникальный ключ в конец сортировки.

ORDER BY и LIMIT

Одна из самых популярных комбинаций в SQL — ORDER BY вместе с LIMIT.

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

Например, нужно получить топ-3 поста по лайкам:

SELECT title, likes
FROM posts
ORDER BY likes DESC
LIMIT 3;

Логика такая:

  1. ORDER BY likes DESC ставит самые популярные посты сверху.
  2. LIMIT 3 оставляет только первые три строки.

Без ORDER BY запрос был бы ошибочным по смыслу:

SELECT title, likes
FROM posts
LIMIT 3;

Такой запрос вернёт просто три строки. Не самые новые, не самые популярные, не самые важные. Просто какие-то три строки, которые базе оказалось удобно вернуть первыми.

Для топов, рейтингов, последних записей и «самых-самых» ORDER BY обязателен.

Пример: последние заказы

Допустим, нужно показать 5 последних заказов.

SELECT id, customer_id, amount, created_at
FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 5;

Почему здесь два поля в сортировке?

created_at DESC ставит свежие заказы выше старых.
id DESC помогает, если несколько заказов созданы в одну и ту же секунду.

Такой запрос подходит для реального интерфейса: порядок будет понятным и стабильным.

Сортировка по выражению

В ORDER BY можно указывать не только готовые колонки, но и выражения.

Например, есть таблица posts с лайками и просмотрами:

id title likes views
1 SQL Basics 50 1000
2 Window Functions 80 400
3 Joins Explained 120 3000

Можно отсортировать посты не просто по лайкам, а по доле лайков от просмотров:

SELECT title, likes, views
FROM posts
ORDER BY likes * 1.0 / views DESC;

В таблице нет отдельной колонки с таким показателем. База посчитает выражение на лету и отсортирует результат по нему.

Здесь 1.0 помогает получить дробное деление, а не целочисленное.

Ещё пример — сортировка по длине имени:

SELECT name
FROM users
ORDER BY LENGTH(name) DESC;

Сначала будут пользователи с самыми длинными именами.

Сортировка по вычисляемой колонке

Часто выражение удобно вывести в SELECT, дать ему понятное имя и потом сортировать по этому имени.

Например:

SELECT
  title,
  likes,
  views,
  likes * 1.0 / views AS engagement_rate
FROM posts
ORDER BY engagement_rate DESC;

Так запрос читается легче:

  • в SELECT мы считаем показатель;
  • в ORDER BY сортируем по нему.

Это особенно удобно в отчётах, где есть расчётные метрики: конверсия, средний чек, CTR, доля от общего числа и так далее.

Сортировка через CASE

Иногда обычная сортировка по алфавиту не подходит.

Например, есть статусы заказов:

  • paid;
  • pending;
  • cancelled.

Если отсортировать по статусу как по строке, база расставит их по алфавиту. Но бизнесу может быть нужен другой порядок: сначала оплаченные, потом ожидающие, потом отменённые.

Для такого случая используют CASE в ORDER BY.

Допустим, есть таблица orders:

id customer amount status created_at
1 Anna 500 paid 2024-03-10
2 Boris 1500 paid 2024-03-15
3 Vera 200 cancelled 2024-03-12
4 Gregory 3000 paid 2024-03-08
5 Denis 800 pending 2024-03-15

Нужно вывести заказы так:

  1. Сначала paid.
  2. Потом pending.
  3. Потом cancelled.
  4. Внутри каждого статуса — новые заказы выше старых.
  5. Если даты одинаковые — большая сумма выше.

Запрос:

SELECT id, customer, status, amount, created_at
FROM orders
ORDER BY
  CASE status
    WHEN 'paid' THEN 1
    WHEN 'pending' THEN 2
    WHEN 'cancelled' THEN 3
    ELSE 4
  END,
  created_at DESC,
  amount DESC;

Результат:

id customer status amount created_at
2 Boris paid 1500 2024-03-15
1 Anna paid 500 2024-03-10
4 Gregory paid 3000 2024-03-08
5 Denis pending 800 2024-03-15
3 Vera cancelled 200 2024-03-12

CASE здесь превращает статусы в условные числа для сортировки:

  • paid получает 1;
  • pending получает 2;
  • cancelled получает 3;
  • всё остальное получает 4.

Так мы сортируем не по алфавиту, а по смыслу.

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

NULL — это отсутствие значения. И при сортировке с ним нужно быть внимательным.

Например, есть статьи, у части из них есть дата публикации, а часть пока в черновиках:

id title published_at
1 SQL SELECT 2024-03-10
2 SQL JOIN NULL
3 SQL ORDER BY 2024-03-15

Если отсортировать по дате, возникает вопрос: куда положить строки с NULL? В начало или в конец?

Разные базы данных ведут себя по-разному.

В PostgreSQL:

  • при ASC значения NULL обычно идут в конце;
  • при DESC значения NULL обычно идут в начале.

В MySQL:

  • при ASC значения NULL обычно идут в начале;
  • при DESC значения NULL обычно идут в конце.

Если ты работаешь в PostgreSQL и хочешь явно управлять положением NULL, используй NULLS FIRST или NULLS LAST.

Например, показать сначала опубликованные статьи от свежих к старым, а черновики без даты оставить в конце:

SELECT title, published_at
FROM articles
ORDER BY published_at DESC NULLS LAST;

А если нужно наоборот — строки без даты поднять наверх:

SELECT title, published_at
FROM articles
ORDER BY published_at DESC NULLS FIRST;

В MySQL синтаксиса NULLS FIRST и NULLS LAST нет. Там часто используют выражение:

SELECT title, published_at
FROM articles
ORDER BY published_at IS NULL, published_at DESC;

published_at IS NULL вернёт условный признак: дата отсутствует или нет. Благодаря этому можно управлять тем, куда попадут строки с пустой датой.

ORDER BY после WHERE

ORDER BY выполняется после фильтрации.

Например, нужно взять только оплаченные заказы и отсортировать их от новых к старым:

SELECT id, customer_id, amount, created_at
FROM orders
WHERE status = 'paid'
ORDER BY created_at DESC;

Сначала WHERE оставит только оплаченные заказы. Потом ORDER BY отсортирует уже отфильтрованный результат.

Порядок частей запроса важен:

SELECT columns
FROM table_name
WHERE condition
ORDER BY column_name;

Нельзя поставить ORDER BY перед WHERE или FROM. SQL ожидает части запроса в своём порядке.

ORDER BY после GROUP BY

ORDER BY часто используют вместе с группировкой.

Например, нужно посчитать выручку по каждому пользователю и отсортировать клиентов по сумме покупок:

SELECT
  customer_id,
  SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
ORDER BY total_amount DESC;

Здесь происходит несколько шагов:

  1. GROUP BY customer_id собирает заказы по клиентам.
  2. SUM(amount) считает сумму заказов каждого клиента.
  3. ORDER BY total_amount DESC ставит клиентов с самой большой суммой наверх.

Так получаются рейтинги, топы и отчёты.

Ещё пример: найти самые активные категории товаров.

SELECT
  category_id,
  COUNT(*) AS products_count
FROM products
GROUP BY category_id
ORDER BY products_count DESC;

Сначала считаем количество товаров в каждой категории, потом сортируем категории по этому количеству.

Можно ли сортировать по колонке, которой нет в SELECT

Обычно да.

Например:

SELECT title
FROM books
ORDER BY rating DESC;

В результате мы выводим только title, но сортируем по rating. Во многих базах данных это нормальная ситуация.

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

Однако есть важный нюанс с DISTINCT.

Например:

SELECT DISTINCT author
FROM books
ORDER BY rating DESC;

Такой запрос может быть проблемным. Почему?

DISTINCT оставляет уникальных авторов. Но у одного автора может быть несколько книг с разными рейтингами. База не всегда может понять, какой именно rating использовать для сортировки автора.

Поэтому с DISTINCT лучше сортировать по тем выражениям, которые есть в результате, или сначала аккуратно агрегировать данные.

Например:

SELECT
  author,
  MAX(rating) AS best_rating
FROM books
GROUP BY author
ORDER BY best_rating DESC;

Теперь всё честно: для каждого автора мы посчитали лучший рейтинг и сортируем именно по нему.

ORDER BY и UNION

Если ты объединяешь результаты через UNION, сортировку обычно пишут один раз в самом конце.

Например:

SELECT name, email
FROM customers
UNION
SELECT name, email
FROM partners
ORDER BY name;

Здесь ORDER BY name сортирует общий результат после объединения.

Не нужно ставить отдельный ORDER BY в каждую часть запроса, если тебе нужен итоговый порядок всей выдачи.

Правильная мысль такая: сначала собрать общий список, потом отсортировать его.

Числа, сохранённые как строки

Одна из неприятных ошибок новичков — хранить числа в текстовой колонке.

Представь, что цены лежат не в числовом типе, а в строковом:

title price_text
A 10
B 2
C 100

Запрос:

SELECT title, price_text
FROM products
ORDER BY price_text;

Может дать такой порядок:

title price_text
A 10
C 100
B 2

Для человека это странно: 2 должно быть раньше 10. Но для строки всё логично: база сравнивает текст посимвольно, а не как числа.

Чтобы отсортировать как числа, можно привести тип:

SELECT title, price_text
FROM products
ORDER BY CAST(price_text AS INTEGER);

Но лучше хранить числа в числовых колонках, а не в строках. Тогда сортировка, фильтрация и расчёты будут работать нормально.

ORDER BY по номеру колонки

SQL позволяет сортировать по номеру колонки из SELECT.

Например:

SELECT title, rating
FROM books
ORDER BY 2 DESC;

2 означает вторую колонку в результате, то есть rating.

Запрос сработает. Но для учебного и рабочего кода это не лучший стиль.

Почему?

Потому что такой запрос хуже читается. Нужно глазами считать, какая колонка в SELECT первая, какая вторая. А если кто-то поменяет порядок колонок, сортировка может случайно измениться.

Лучше писать явно:

SELECT title, rating
FROM books
ORDER BY rating DESC;

Так понятнее и тебе, и человеку, который будет читать запрос после тебя.

Частые ошибки с ORDER BY

Думать, что порядок есть сам по себе

Самая частая ошибка: считать, что база вернёт строки в порядке добавления.

Например:

SELECT id, title
FROM posts;

Может показаться, что посты будут идти по id. Но SQL этого не обещает.

Нужен порядок по id — напиши явно:

SELECT id, title
FROM posts
ORDER BY id;

Нужны свежие посты — тоже явно:

SELECT id, title, created_at
FROM posts
ORDER BY created_at DESC, id DESC;

Использовать LIMIT без ORDER BY

Плохо:

SELECT id, title
FROM posts
LIMIT 10;

Так ты получишь просто 10 строк. Не топ, не последние, не первые по смыслу.

Хорошо:

SELECT id, title, created_at
FROM posts
ORDER BY created_at DESC, id DESC
LIMIT 10;

Теперь это действительно 10 последних постов.

Забыть направление сортировки

Если написать просто ORDER BY created_at, база отсортирует по возрастанию. То есть сначала будут самые старые даты.

Для ленты новостей обычно нужно наоборот:

SELECT title, created_at
FROM posts
ORDER BY created_at DESC;

Не добавить второй критерий при одинаковых значениях

Плохо:

SELECT id, title, rating
FROM books
ORDER BY rating DESC;

Если у нескольких книг одинаковый рейтинг, порядок между ними не гарантирован.

Лучше:

SELECT id, title, rating
FROM books
ORDER BY rating DESC, id ASC;

Теперь сортировка стабильнее.

Сортировать текстовые числа как настоящие числа

Если колонка строковая, сортировка будет строковой:

SELECT title, price_text
FROM products
ORDER BY price_text;

Если данные уже такие, можно привести тип:

SELECT title, price_text
FROM products
ORDER BY CAST(price_text AS INTEGER);

Но правильнее хранить цену в числовой колонке.

Главное

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

Без него база не гарантирует порядок. Даже если тебе кажется, что строки «и так идут нормально», это случайность, а не правило.

Главные шаблоны:

SELECT title, price
FROM products
ORDER BY price;
SELECT title, price
FROM products
ORDER BY price DESC;
SELECT name, department, salary
FROM employees
ORDER BY department ASC, salary DESC;
SELECT title, created_at
FROM posts
ORDER BY created_at DESC, id DESC
LIMIT 10;

Запомни:

  • ASC — по возрастанию;
  • DESC — по убыванию;
  • ASC можно не писать, он используется по умолчанию;
  • несколько колонок в ORDER BY дают многоуровневую сортировку;
  • ORDER BY вместе с LIMIT позволяет делать топы и последние записи;
  • для стабильного порядка добавляй уникальную колонку, например id;
  • с NULL и строковыми числами нужно быть особенно внимательным.

ORDER BY — это не украшение запроса, а способ превратить набор строк в понятный список. Именно с него начинается нормальная выдача: товары становятся отсортированными, отчёты — читаемыми, ленты — свежими, а топы — честными.

Закрепи на практике

Решай задачи в SQL-тренажёре с мгновенной проверкой и подсказками.

Открыть тренажёр