> SmartGate

CASE

Условная логика внутри SQL-запроса

Теория

Представим ситуацию. В таблице в столбце salary записана зарплата сотрудников в виде числа: 65000, 90000, 120000. Но нам захотелось посмотреть не просто на числа, а на понятные категории зарплат: 'базовая', 'средняя', 'высокая', то есть разбить все зарплаты на три общие категории. Или, например, в таблице у части пользователей город не указан, и в результате хочется увидеть не значение NULL вместо зарплаты, а фразу 'город не указан'.

Существует интересная конструкция, ее еще часто называют условной, называется она CASE. Она позволяет добавить в запрос условную логику: если для строки выполняется одно условие — вернуть одно значение, если другое — вернуть другое.

Таким образом в CASE задается набор правил прямо внутри запроса. SQL берёт значения указанного в CASE столбца, проверяет их по этим правилам и возвращает результат, который вы сами определили, если для значения правило выполняется.

Важно: CASE ничего не меняет в таблице, а только показывает данные в более удобном виде в результате SELECT или помогает задать свою логику сортировки в ORDER BY или выполняет гибкие вычисления.

Синтаксис

SELECT column1,
       column2,
       CASE                            -- начало конструкции
           WHEN condition THEN result  -- проверяется первое условие, если не подошло...
           WHEN condition THEN result  -- проверяется второе условие, если не подошло...
           ELSE result                 -- проверяется последнее третье условие
       END AS column3                  -- конец конструкции и присвоение ей псевдонима
FROM table_name;
SQL
Как работает:

• после WHEN пишется условие, которое нужно проверить;
• после THEN пишется значение, которое нужно получить, если условие выполнилось;
• ELSE — применяется как последнее условие, если все предыдущие не были выполнены.

CASE анализирует условия последовательно, начиная с верхнего. Если для текущей строки условие оказывается верным, SQL немедленно выбирает значение, указанное в соответствующем THEN, и прекращает дальнейшую проверку.

Поэтому порядок расположения условий очень важен. Сначала обычно ставят более точные или более приоритетные условия, а потом уже всё остальное. Или условие четко определяют нижней и верхней границей через AND.

Если ELSE не написать, то для строк, которые не попали ни под одно условие, результатом будет NULL. Иногда это планируемое поведение, но лучше явно указать, что нужно вернуть по умолчанию.

Важно: всю конструкцию CASE ... END можно назвать через псевдоним так же, как обычный вычисляемый столбец. Поэтому в примерах ниже после END стоит AS new_salary, AS city_label или AS status_label.

Примеры

1. Считаем новую зарплату по разным правилам повышения

Используем CASE для вычисления нового числового значения. Если зарплата меньше 70000 рублей, она увеличивается на 20%. Если зарплата находится в диапазоне от 70000 до 99999 рублей, она повышается на 10%. В остальных случаях зарплата остаётся неизменной.

🔄 Попробуйте изменить запрос:

  • • Поменяйте в обоих условиях границу 70000 на 80000 и посмотрите, кому теперь попадёт повышение 20%
  • • В первом условии напишите < 100000 вместо < 70000 и проверьте, дойдет ли дело до второго условия WHEN salary BETWEEN 70000 AND 99999 THEN salary * 1.10

2. Показываем вместо пустого города понятный текст

Если город указан, показываем его название. Если города нет, то вместо NULL выводим понятный текст. Для интерфейсов и отчётов удобнее.

🔄 Попробуйте изменить запрос:

  • • Замените текст 'город не указан' на 'нет данных'
  • • Отсортируйте результат по вычисляемому столбцу: ORDER BY city_label ASC

3. Расшифровываем статусы заказов в более понятный вид

Еще один интересный сценарий для CASE: категоризовать значения по более понятным и удобным формулировкам.

🔄 Попробуйте изменить запрос:

  • • Сделайте для 'доставлен' отдельную подпись, убрав его из IN
  • • Поменяйте текст 'Статус не указан' на 'Ожидает обработки'

4. Сортируем пользователей по своему правилу

Обычно оператор ORDER BY city сортирует города по алфавиту. Однако в некоторых случаях требуется задать собственный порядок. В этом примере мы самостоятельно определяем приоритеты: сначала идёт 'Москва', затем 'Алматы', после чего следуют остальные города. Строки, не содержащие информацию о городе, перемещаются в конец списка.

🔄 Попробуйте изменить запрос:

  • • Поставьте строки без города в начало, изменив число у ветки WHEN city IS NULL
  • • Поменяйте местами приоритеты для 'Москва' и 'Алматы'

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

Ставят условия в неудачном порядке CASE идёт сверху вниз. Если верхнее условие уже подходит строке, остальные условия ниже для этой строки уже не проверяются. Поэтому сначала лучше ставить более точные условия, а потом более общие. Забывают про ELSE Если ни одно условие не подошло, а ELSE нет, результатом будет NULL. Иногда это нормально, но чаще пользователь просто увидит пустое значение и не поймёт, почему так произошло. Вместо ELSE можно также указать еще одну ветку THEN, в которой указать все остальные случаи. Пытаются обрабатывать NULL как обычное значение Если нужно отдельно поймать пустое значение, надёжнее писать WHEN column IS NULL THEN .... Это понятнее и работает предсказуемо. Думают, что CASE меняет данные в таблице Нет, не меняет. Он только вычисляет значение в результате запроса. В самой таблице ничего не переписывается.

Практика

Проверь себя

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

1
Что вернёт CASE, если ни одно условие не подошло, а ELSE не указан?
2
Почему в конструкции ниже порядок веток важен?
CASE WHEN price >= 50000 THEN 'дорогой' WHEN price >= 100000 THEN 'премиум' ELSE 'обычный' END
3
Напишите запрос, который выведет product_id, product_name, price и новый столбец price_group из таблицы products. Логика такая: если цена меньше 50000 — 'бюджетный', если цена от 50000 до 99999 — 'средний', иначе — 'премиум'.
4
Какой вариант правильно показывает, что всей конструкции CASE ... END можно дать псевдоним?
5
Напишите запрос, который выведет worker_id, first_name, salary и столбец salary_label из таблицы workers. Логика такая: если зарплата не указана — вернуть 'не указана', если зарплата меньше 80000 — вернуть 'ниже 80000', иначе — '80000 и выше'. Результат отсортируйте по дате найма от более ранних к более поздним.
6
Что вернёт выражение CASE WHEN 10 > 20 THEN 1 ELSE 0 END? Введите только число.
7
Напишите запрос, который выведет product_id, product_name, category и price из таблицы products, а сортировка должна работать по такому правилу: сначала товары категории 'Смартфоны', потом 'Ноутбуки', потом товары без категории, а после них — все остальные. Внутри каждой группы более дорогие товары должны идти выше.