ORDER BY в SQL: как отсортировать по двум столбцам с ASC и DESC

Чтобы отсортировать результат по двум столбцам в разных направлениях, укажите ASC или DESC после каждого: ORDER BY department ASC, salary DESC.

Разбираем, почему DESC действует только на один столбец, где окажутся NULL в PostgreSQL, MySQL и SQLite и как сделать порядок строк одинаковым при каждом запуске.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3156 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3810 экспертных мнений Подписаться на Телеграм-канал
Обложка: ORDER BY в SQL: как отсортировать по двум столбцам с ASC и DESC

Чтобы отсортировать результат запроса по двум столбцам в разных направлениях, перечислите их через запятую и поставьте ASC или DESC после каждого: ORDER BY department ASC, salary DESC. База сначала выстроит строки по отделу от А до Я, а внутри каждого отдела поставит сотрудников от большей зарплаты к меньшей.

Направление относится только к тому столбцу, за которым стоит. Это самая частая ошибка новичков, поэтому ниже разберём её отдельно, а заодно посмотрим, куда при сортировке попадают пустые значения NULL. Примеры выполнены в PostgreSQL 17, MySQL 8.0 и SQLite 3.51. Если вы только знакомитесь с запросами, начните с разбора команды SELECT в MySQL.

Как работает ORDER BY: синтаксис, ASC и DESC

Рой-аналитик сортирует таблицу запросом ORDER BY

ORDER BY пишут в конце запроса, после WHERE, GROUP BY и HAVING. Дальше может идти только LIMIT с OFFSET. Как группировать строки и считать их по группам, мы разбирали в статье про функцию COUNT.

SELECT столбцы
FROM таблица
WHERE условие
ORDER BY столбец_1 [ASC | DESC], столбец_2 [ASC | DESC];

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

  • ASC (ascending), по возрастанию: от меньшего числа к большему, от ранней даты к поздней, от А до Я;
  • DESC (descending), по убыванию, в обратную сторону.

Если направление не указано, база сортирует по возрастанию. Так прямо написано в документации SQLite и в справке Microsoft по SQL Server: «Порядок сортировки по умолчанию — ASC». Поэтому ORDER BY salary и ORDER BY salary ASC дают одно и то же.

Дальше работаем с маленькой таблицей сотрудников. Восемь строк, у Жанны зарплата не заполнена:

id name department salary hired
1 Анна Продажи 90000 2023-03-01
2 Борис Разработка 180000 2021-07-15
3 Вера Продажи 120000 2022-01-10
4 Глеб Разработка 150000 2024-02-05
5 Дина Маркетинг 110000 2022-09-20
6 Егор Разработка 180000 2020-11-30
7 Жанна Маркетинг NULL 2025-01-13
8 Зоя Продажи 90000 2024-06-03

Сортировка по убыванию зарплаты в MySQL:

SELECT name, salary FROM employees ORDER BY salary DESC;

Борис   180000
Егор    180000
Глеб    150000
Вера    120000
Дина    110000
Анна     90000
Зоя      90000
Жанна    NULL

Сортировка по двум столбцам: ASC и DESC в одном запросе

Карточки разложены по группам и упорядочены внутри каждой

Второй столбец в ORDER BY работает как запасной ключ. База смотрит на него только там, где значения первого столбца совпали.

  1. Строки делятся на группы по первому столбцу и выстраиваются в его порядке.
  2. Внутри каждой группы с одинаковым значением база сортирует по второму столбцу.
  3. Если совпали оба, в ход идёт третий, и так далее.

Запрос «отделы по алфавиту, внутри отдела сначала самые высокие зарплаты»:

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

Дина    Маркетинг    110000
Жанна   Маркетинг    NULL
Вера    Продажи      120000
Анна    Продажи       90000
Зоя     Продажи       90000
Борис   Разработка   180000
Егор    Разработка   180000
Глеб    Разработка   150000

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

Похожий пример с датами: при равной зарплате выше поставить того, кто дольше работает в компании. Для этого добавляем hired ASC вторым ключом:

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

Егор    180000   2020-11-30
Борис   180000   2021-07-15
Глеб    150000   2024-02-05
...
Канал основателя Checkroi Вани Буявца3 800 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Главная ошибка: DESC действует только на один столбец

Рой радуется, что исправил порядок сортировки в запросе

Частая ситуация: человек пишет ORDER BY department, salary DESC и ждёт, что по убыванию отсортируются оба столбца. На деле DESC относится только к salary, а department сортируется по умолчанию, то есть по возрастанию.

В документации PostgreSQL этот случай разобран прямо: ORDER BY x, y DESC означает ORDER BY x ASC, y DESC, и это не то же самое, что ORDER BY x DESC, y DESC.

Что написали Что получили
ORDER BY department, salary DESC Маркетинг → Продажи → Разработка, зарплата внутри отдела по убыванию
ORDER BY department DESC, salary DESC Разработка → Продажи → Маркетинг, зарплата внутри отдела по убыванию
ORDER BY department DESC, salary Разработка → Продажи → Маркетинг, зарплата внутри отдела по возрастанию

Решение: ставьте ASC или DESC явно после каждого столбца, даже там, где хватило бы умолчания. Запрос станет длиннее на пару слов, зато через месяц вы прочитаете его без догадок.

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

CheckroiCheckroiПодборка курсов по SQL422 курса • 40 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Где окажутся NULL при сортировке

NULL означает, что значение не заполнено, с нулём и пустой строкой его путать нельзя (подробнее в статье про NULL в SQL). Такие строки разные СУБД ставят по-разному. Тот же запрос с DESC в PostgreSQL выводит NULL первой строкой, а в MySQL последней. Вот вывод PostgreSQL для ORDER BY salary DESC:

 name  | salary
-------+--------
 Жанна |
 Борис | 180000
 Егор  | 180000
 ...

Сводка по четырём СУБД, ссылки на документацию под таблицей:

СУБД NULL при ASC NULL при DESC NULLS FIRST / NULLS LAST
PostgreSQL в конце в начале есть
MySQL в начале в конце нет, синтаксическая ошибка
SQLite в начале в конце есть
SQL Server в начале в конце нет в синтаксисе ORDER BY

PostgreSQL считает NULL больше любого значения, поэтому NULLS FIRST там по умолчанию для DESC (документация PostgreSQL). SQLite, наоборот, считает NULL меньше любого значения (документация SQLite). MySQL выводит NULL первыми при ASC и последними при DESC (справка MySQL), у SQL Server NULL тоже наименьшие (справка Microsoft).

Почему это важно: запрос «двое сотрудников с самой высокой зарплатой» в PostgreSQL вернёт Жанну, у которой зарплаты нет вовсе.

SELECT name FROM employees ORDER BY salary DESC LIMIT 2;
-- PostgreSQL: Жанна, Борис

SELECT name FROM employees ORDER BY salary DESC NULLS LAST LIMIT 2;
-- PostgreSQL: Борис, Егор
CheckroiCheckroiПодборка курсов по PostgreSQL158 курсов • 27 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

В MySQL на NULLS LAST будет ошибка 1064. Там NULL отправляют в конец отдельным ключом сортировки. Вариант с CASE мы выполнили в MySQL, PostgreSQL и SQLite, а в справке Microsoft сортировка через CASE разобрана на примерах:

SELECT name, salary
FROM employees
ORDER BY CASE WHEN salary IS NULL THEN 1 ELSE 0 END, salary DESC;

Строки с NULL получают 1, остальные 0, и пустые зарплаты уходят вниз при любом направлении. В MySQL и PostgreSQL то же самое можно записать короче: ORDER BY salary IS NULL, salary DESC. Если NULL нужно не убрать вниз, а заменить на ноль или текст, поможет функция COALESCE.

Сортировка по выражению, псевдониму и номеру столбца

После ORDER BY можно ставить не только имя столбца из таблицы.

Псевдоним из SELECT

SELECT name, salary * 12 AS year_pay
FROM employees
ORDER BY year_pay DESC;

Псевдоним работает везде, если стоит в ORDER BY один. С выражением сложнее: ORDER BY year_pay + 1 MySQL выполнит, а PostgreSQL ответит ошибкой «столбец year_pay не существует». В документации PostgreSQL это ограничение описано отдельно: имя выходного столбца нельзя использовать внутри выражения, только само по себе.

Номер столбца

ORDER BY 2, 3 DESC сортирует по второму и третьему столбцу из списка SELECT. В запросе SELECT name, department, salary это отдел и зарплата.

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

Свой порядок через CASE

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

SELECT name, department
FROM employees
ORDER BY CASE department
           WHEN 'Разработка' THEN 1
           WHEN 'Продажи'    THEN 2
           ELSE 3
         END,
         name;

Борис   Разработка
Глеб    Разработка
Егор    Разработка
Анна    Продажи
Вера    Продажи
Зоя     Продажи
Дина    Маркетинг
Жанна   Маркетинг

Больше приёмов с этим оператором собрано в разборе CASE в SQL на примерах.

Частые ошибки и что с ними делать

Одинаковые значения меняют порядок от запуска к запуску

Борис и Егор получают одинаково. В наших прогонах первым во всех трёх СУБД шёл Борис, но это совпадение: после изменения данных или при другом плане запроса первым может оказаться Егор. И такой результат тоже будет верным: если значения совпали, порядок между такими строками ничем не задан.

Решение: добавляйте последним ключом уникальный столбец, обычно id. Особенно это важно для запросов с LIMIT. Документация PostgreSQL про LIMIT предупреждает: если ORDER BY не задаёт строкам однозначный порядок, вы получите непредсказуемый набор строк.

SELECT name, salary FROM employees ORDER BY salary DESC, id LIMIT 3;

Числа в текстовом столбце сортируются как строки

Если номера заказов или артикулы хранятся в VARCHAR, база сравнивает их посимвольно. В наших прогонах все три СУБД выдали одно и то же: 10, 100, 25, 9.

Решение: приведите значение к числу прямо в ORDER BY. В PostgreSQL и SQLite подходит CAST(v AS INT). MySQL такую запись не принимает, ему нужен CAST(v AS SIGNED) или UNSIGNED (справка MySQL по CAST). После приведения порядок правильный: 9, 10, 25, 100.

CheckroiCheckroiПодборка курсов по MySQL71 курс • 17 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

DISTINCT и сортировка по столбцу не из SELECT

Обычно сортировать можно и по полю, которого нет в выводе: SELECT name FROM employees ORDER BY hired DESC работает везде. С DISTINCT так нельзя. PostgreSQL и MySQL отвечают ошибкой, потому что одному уникальному отделу соответствует несколько зарплат и непонятно, по какой из них ставить строку. SQLite запрос выполнит без ошибки, но по какой из зарплат он поставил каждый отдел, из запроса не понять.

Решение: добавьте этот столбец в SELECT или сгруппируйте и сортируйте по агрегату, например ORDER BY MAX(salary). Как работают уникальные значения, объясняем в статье про DISTINCT.

Медленная сортировка на большой таблице

Для частого запроса с ORDER BY и LIMIT помогает индекс по тем же столбцам в том же порядке. Индекс (department, salary) закрывает и ORDER BY department, salary, и обратный порядок по обоим столбцам. А вот для смешанного department ASC, salary DESC PostgreSQL предлагает отдельный индекс (department ASC, salary DESC) (раздел документации про индексы и ORDER BY).

Мы проверили это на таблице в 200 тысяч строк. С обычным индексом PostgreSQL 17 досортировывал зарплаты отдельным шагом Incremental Sort. Со смешанным индексом план свёлся к одному чтению индекса.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 800 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Где освоить SQL системно

ORDER BY осваивают в SQL одним из первых. Дальше идут соединение таблиц через JOIN, группировка и оконные функции, где ORDER BY появляется ещё раз внутри OVER. Всё это последовательно разбирают на курсах. Ниже подборка из каталога Checkroi, а если вы присматриваетесь к профессии, посмотрите план, как стать SQL-разработчиком.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Нейросети для рабочих задач
Перейти на сайт курса
SkillboxSkillbox31 290 ₽ - 1 месяцОбзор курса
SQL для анализа данных
Перейти на сайт курса
SkillboxSkillbox50 865 ₽6203 ₽/мес.2 месяцаОбзор курса
SQL-разработчик: тариф PRO
Перейти на сайт курса
Академия ЭдюсонЭдюсон89 900 ₽7491 ₽/мес.2 месяцаОбзор курса
SQL-разработчик: тариф Базовый
Перейти на сайт курса
Академия ЭдюсонЭдюсон79 900 ₽3329 ₽/мес.3 месяцаОбзор курса
Data-Driven подход в разработке продукта: SQL и Yandex DataLens
Перейти на сайт курса
ProductStarProductStar29 990 ₽2999 ₽/мес.1 месяцОбзор курса

Больше программ — в полном каталоге курсов по SQL

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

Что значит ASC и DESC в SQL?

ASC сортирует по возрастанию: от меньшего числа к большему, от ранней даты к поздней, от А до Я. DESC сортирует по убыванию. Слово ставят после столбца в ORDER BY, например ORDER BY salary DESC.

Как по умолчанию сортирует ORDER BY?

По возрастанию, то есть как ASC. Запросы ORDER BY salary и ORDER BY salary ASC возвращают строки в одном порядке.

Как отсортировать по двум столбцам в разных направлениях?

Перечислите столбцы через запятую и укажите направление у каждого: ORDER BY department ASC, salary DESC. Второй столбец влияет на порядок только там, где значения первого совпали.

Почему DESC не сработал для первого столбца?

DESC относится только к столбцу, после которого стоит. В записи ORDER BY department, salary DESC отдел сортируется по возрастанию. Чтобы оба столбца шли по убыванию, нужен DESC после каждого.

Как вывести NULL в конце сортировки в MySQL?

NULLS LAST в MySQL не работает, запрос упадёт с ошибкой 1064. Добавьте отдельный ключ: ORDER BY salary IS NULL, salary DESC или вариант с CASE, который понимают и другие СУБД.

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

Да, SELECT name FROM employees ORDER BY hired DESC работает в PostgreSQL, MySQL и SQLite. Исключение составляет SELECT DISTINCT: PostgreSQL и MySQL требуют, чтобы столбец из ORDER BY стоял в списке выборки.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!