Логотип Workflow

Article

Updated at:

Select Where Order

Stage 3. SELECT, фильтрация, сортировка и форма результата

В этой теме важно понять не только синтаксис, но и порядок мышления. SQL-запрос на чтение обычно строится как конвейер: сначала мы определяем, какие поля хотим видеть, затем указываем источник данных, потом отсекаем лишние строки, после этого задаем порядок, и только в конце ограничиваем размер ответа.

SELECT flow diagram

Базовый скелет запроса:

SELECT ...
FROM ...
WHERE ...
ORDER BY ...
LIMIT ...;

Ниже разберем каждый блок отдельно и подробно.

Блок 1. SELECT: форма результата и зачем она важна

SELECT определяет итоговую структуру ответа. По сути, вы описываете “какие колонки увидит клиент”.

Простой пример:

SELECT id, user_id, amount, status, created_at
FROM orders;

Этот запрос возвращает только перечисленные колонки. Это важно по нескольким причинам:

  1. Меньше лишних данных. Если вы выбираете только нужные поля, запрос читает и передает меньше информации.

  2. Понятный контракт. Если endpoint или отчет ожидает конкретные поля, явный SELECT фиксирует этот контракт.

  3. Меньше риска утечки. SELECT * может случайно включить служебные или чувствительные поля.

Частая ошибка новичков: использовать SELECT * “для удобства”. В обучении можно, но в рабочем коде лучше явный список полей.

Алиасы в SELECT

Когда имена длинные или конфликтуют, используйте AS:

SELECT
  id AS order_id,
  amount AS order_amount
FROM orders;

Алиасы делают результат читаемее и удобнее для frontend/DTO.

Блок 2. WHERE: что такое условие и как оно работает

WHERE — это фильтр строк. Он отвечает на вопрос: “Какие записи должны остаться?”.

Пример:

SELECT id, amount, status
FROM orders
WHERE status = 'PAID';

После такого фильтра в выдаче будут только оплаченные заказы.

Логические операторы

WHERE почти всегда строится из нескольких условий:

SELECT id, user_id, amount, status, created_at
FROM orders
WHERE status = 'PAID'
  AND amount >= 500
  AND created_at >= DATE '2026-05-01';

Здесь строка пройдет фильтр только если выполняются все три условия.

Можно использовать OR:

WHERE status = 'PAID' OR status = 'SHIPPED'

И IN как более удобную запись:

WHERE status IN ('PAID', 'SHIPPED')

WHERE и NULL

NULL нельзя проверять через =:

-- неправильно
WHERE paid_at = NULL

-- правильно
WHERE paid_at IS NULL

Это критично, потому что неправильная проверка часто дает “пустой результат” и ломает логику.

Порядок применения

WHERE отрабатывает до сортировки и до LIMIT. Поэтому фильтрация обычно сильнее всего влияет на производительность: чем раньше вы отсекли лишние строки, тем меньше работы дальше.

Блок 3. ORDER BY: зачем нужна сортировка

ORDER BY задает порядок строк в результате. Если сортировку не указать, порядок не гарантирован.

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

DESC — от новых к старым. ASC — от старых к новым.

Почему одной сортировки иногда недостаточно

Если у двух строк одинаковый created_at, порядок между ними может “прыгать”. Для стабильности добавляют второй ключ:

ORDER BY created_at DESC, id DESC

Это особенно важно для пагинации.

Сортировка по тексту и числам

  • Числа сортируются как числа (100 > 20).
  • Текст сортируется по правилам collation (языковые правила могут отличаться).

Поэтому для пользовательских списков заранее определяйте, по какому полю и в каком направлении сортируете.

LIMIT: контроль объема результата

LIMIT ограничивает число возвращаемых строк.

SELECT id, user_id, amount, status, created_at
FROM orders
WHERE status = 'PAID'
ORDER BY created_at DESC, id DESC
LIMIT 5;

Смысл: после фильтра и сортировки вернуть только первые 5 строк.

Почему LIMIT нужен почти всегда:

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

Полный разбор одного запроса

SELECT id, user_id, amount, status, created_at
FROM orders
WHERE status = 'PAID'
ORDER BY created_at DESC, id DESC
LIMIT 5;

Как это выполняется логически:

  1. Берем таблицу orders.
  2. Оставляем только строки со статусом PAID.
  3. Сортируем оставшиеся строки от новых к старым.
  4. Если даты равны — сортируем по id.
  5. Возвращаем только первые 5 строк.

Пример результата

iduser_idamountstatuscreated_at
152900.00PAID2026-05-10 12:15
1411200.00PAID2026-05-10 11:01
122700.00PAID2026-05-10 10:40
91450.00PAID2026-05-10 10:05
73300.00PAID2026-05-10 09:58

Частые ошибки новичков

  1. SELECT * вместо явного списка полей.
  2. Отсутствие ORDER BY в пользовательском списке.
  3. Неверная работа с NULL (= NULL вместо IS NULL).
  4. Слишком широкий WHERE (в ответе “слишком много мусора”).
  5. Отсутствие LIMIT на больших таблицах.

Практика перед следующим уроком

Выполните шаги в этом порядке.

Шаг 1. Добавьте тестовые заказы:

INSERT INTO orders(user_id, amount, status, created_at) VALUES
(1, 1200.00, 'PAID', '2026-05-10 12:00:00'),
(1, 300.00,  'NEW',  '2026-05-10 11:00:00'),
(2, 700.00,  'PAID', '2026-05-10 10:00:00'),
(2, 950.00,  'PAID', '2026-05-10 09:00:00'),
(3, 150.00,  'CANCELLED', '2026-05-10 08:00:00');

Шаг 2. Запустите базовый запрос без фильтра:

SELECT id, user_id, amount, status, created_at
FROM orders;

Шаг 3. Добавьте фильтрацию:

SELECT id, user_id, amount, status, created_at
FROM orders
WHERE status = 'PAID';

Шаг 4. Добавьте сортировку и ограничение:

SELECT id, user_id, amount, status, created_at
FROM orders
WHERE status = 'PAID'
ORDER BY created_at DESC, id DESC
LIMIT 5;

Что проверить в конце:

  • остались только PAID;
  • сверху самая новая дата;
  • не больше 5 строк.