ORDER BY сортирует строки результата. Без него порядок строк не гарантирован — даже если вчера данные вернулись в нужном порядке, завтра может быть иначе.
Базовый синтаксис
SELECT name, salary FROM employees ORDER BY salary; -- по возрастанию
SELECT name, salary FROM employees ORDER BY salary DESC; -- по убыванию
SELECT name, salary FROM employees ORDER BY salary ASC; -- явно по возрастанию
По умолчанию — ASC (ascending, возрастание).
Сортировка по нескольким колонкам
-- Сначала по отделу, внутри — по зарплате убыванию
SELECT name, department, salary
FROM employees
ORDER BY department ASC, salary DESC;
Каждая колонка сортируется независимо и может иметь своё направление.
Сортировка по номеру колонки
-- Вместо названия — порядковый номер из SELECT
SELECT name, department, salary FROM employees ORDER BY 3 DESC;
-- 3 = salary
Удобно в интерактивных запросах, но в продакшн-коде лучше писать явно — сложнее читать.
Сортировка по выражению
-- По длине имени
SELECT name FROM users ORDER BY LENGTH(name);
-- По вычисляемому полю
SELECT product, price, quantity, price * quantity AS total
FROM order_items
ORDER BY price * quantity DESC;
-- По псевдониму из SELECT
SELECT product, price * quantity AS total
FROM order_items
ORDER BY total DESC;
NULL в сортировке
-- По умолчанию в PostgreSQL NULL идут последними при ASC, первыми при DESC
SELECT name, score FROM users ORDER BY score DESC;
-- NULL окажутся первыми
-- Явное управление
SELECT name, score FROM users ORDER BY score DESC NULLS LAST;
SELECT name, score FROM users ORDER BY score ASC NULLS FIRST;
CASE WHEN в ORDER BY
-- Кастомный порядок: сначала 'active', потом 'pending', потом остальные
SELECT name, status FROM users
ORDER BY
CASE status
WHEN 'active' THEN 1
WHEN 'pending' THEN 2
ELSE 3
END;
-- VIP клиенты сверху, потом по алфавиту
SELECT name, tier FROM customers
ORDER BY
CASE WHEN tier = 'VIP' THEN 0 ELSE 1 END,
name;
ORDER BY с LIMIT
-- Топ-10 по выручке
SELECT user_id, SUM(amount) AS revenue
FROM orders
GROUP BY user_id
ORDER BY revenue DESC
LIMIT 10;
-- Пагинация
SELECT * FROM products
ORDER BY created_at DESC
LIMIT 20 OFFSET 40; -- страница 3 (по 20 на странице)
ORDER BY в подзапросах
ORDER BY в подзапросе не гарантирует порядок во внешнем запросе:
-- Порядок здесь определяется внешним ORDER BY, не внутренним
SELECT * FROM (
SELECT * FROM orders ORDER BY amount DESC -- не влияет на итог
) sub
ORDER BY created_at; -- этот ORDER BY определяет результат
Производительность
ORDER BY может быть дорогой операцией на больших таблицах — базе нужно отсортировать весь результат. Индекс по колонке сортировки может значительно ускорить запрос.
-- Если часто делаете ORDER BY created_at DESC — нужен индекс
CREATE INDEX idx_orders_created_at ON orders(created_at DESC);
Порядок выполнения
ORDER BY выполняется почти последним:
- FROM
- WHERE
- GROUP BY
- HAVING
- SELECT
- ORDER BY
- LIMIT
Поэтому в ORDER BY можно использовать псевдонимы из SELECT:
SELECT user_id, COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
ORDER BY orders_count DESC; -- псевдоним работает