CASE WHEN: условные выражения

CASE WHEN: условные выражения

В предыдущих уроках вы освоили специальные операторы: LIKE для шаблонов, IN для списков, BETWEEN для диапазонов, IS NULL для проверки на отсутствие значения. Завершим этот модуль мощным инструментом — CASE WHEN. Это аналог конструкции if-else из обычных языков программирования, реализованный прямо внутри SQL. Он позволяет добавить условную логику в SELECT-список, создавая вычисляемые колонки на основе ветвления.

Что такое CASE WHEN

CASE WHEN — это выражение (не оператор!), которое вычисляет разные значения в зависимости от условия. Поскольку это выражение, его можно использовать везде, где допустимо выражение: в SELECT-списке, в ORDER BY, в агрегатных функциях (об этом в модуле 5).

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

CASE
  WHEN условие1 THEN результат1
  WHEN условие2 THEN результат2
  ...
  ELSE результат_по_умолчанию
END

СУБД проверяет условия сверху вниз. Как только нашлось первое истинное (TRUE) условие — возвращается соответствующий результат, остальные условия не проверяются. Если ни одно условие не истинно — возвращается ELSE. Если ELSE не указан — возвращается NULL.

Простой пример: метки по диапазону

Задача: добавить к товарам текстовую метку цены.

SELECT name,
       price,
       CASE
         WHEN price < 1000  THEN 'бюджетный'
         WHEN price < 5000  THEN 'средний'
         WHEN price < 20000 THEN 'дорогой'
         ELSE                    'премиум'
       END AS price_category
FROM   products;

Результат:

name        | price | price_category
------------+-------+---------------
Мышь        | 800   | бюджетный
Клавиатура  | 2500  | средний
Монитор     | 12000 | дорогой
Ноутбук     | 55000 | премиум

Каждая строка получила категорию на основе значения price. Важно: условия проверяются по порядку. Для price = 2500 первое условие < 1000 — ложно, второе < 5000 — истинно, возвращается «средний». Дальнейшие условия уже не проверяются.

Проверь себя: какую категорию получит товар с price = 5000?

Синтаксис CASE с равенством (CASE value WHEN)

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

CASE колонка
  WHEN значение1 THEN результат1
  WHEN значение2 THEN результат2
  ELSE результат_по_умолчанию
END

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

SELECT order_id,
       CASE status
         WHEN 'pending'   THEN 'Ожидает обработки'
         WHEN 'shipped'   THEN 'Отправлен'
         WHEN 'delivered' THEN 'Доставлен'
         WHEN 'cancelled' THEN 'Отменён'
         ELSE                  'Неизвестный статус'
       END AS status_ru
FROM   orders;

Эта форма (CASE колонка WHEN значение) — синтаксический сахар для CASE WHEN колонка = значение. Оба варианта дают одинаковый результат, но для простых проверок на равенство короткая форма читабельнее.

CASE WHEN в ORDER BY

CASE WHEN можно использовать в ORDER BY для нестандартной сортировки:

SELECT name, status
FROM   orders
ORDER BY
  CASE status
    WHEN 'urgent'   THEN 1
    WHEN 'pending'  THEN 2
    WHEN 'shipped'  THEN 3
    ELSE                 4
  END;

Заказы отсортированы в кастомном порядке: сначала срочные, затем ожидающие, затем отправленные, затем всё остальное. Обычная сортировка по строкам дала бы алфавитный порядок — «pending, shipped, urgent» — что не соответствует смысловому приоритету.

CASE WHEN с IS NULL

CASE WHEN прекрасно обрабатывает NULL:

SELECT name,
       CASE
         WHEN phone IS NULL THEN 'не указан'
         ELSE phone
       END AS contact_phone
FROM   customers;

Вместо пустого поля — понятный текст «не указан». Фактически это то же самое, что COALESCE(phone, 'не указан'), но CASE WHEN гибче: можно написать разную логику для разных условий.

Вложенные условия в CASE

Условие в WHEN может быть произвольным логическим выражением — с AND, OR, NOT, вызовами функций:

SELECT name,
       salary,
       CASE
         WHEN department = 'Разработка' AND salary > 100000 THEN 'Senior Dev'
         WHEN department = 'Разработка' AND salary > 60000  THEN 'Dev'
         WHEN department = 'Менеджмент'                     THEN 'Manager'
         ELSE 'Другой'
       END AS role_label
FROM   employees;

Можно комбинировать CASE с другими операторами, которые вы изучили — IN, BETWEEN, LIKE:

SELECT name,
       email,
       CASE
         WHEN email LIKE '%@gmail.com'  THEN 'Gmail'
         WHEN email LIKE '%@yandex.ru'  THEN 'Яндекс'
         WHEN email IN (SELECT email FROM corporate_emails) THEN 'Корпоратив'
         ELSE 'Другое'
       END AS email_provider
FROM   customers;

CASE WHEN в WHERE

Технически CASE WHEN можно использовать в WHERE, хотя это встречается реже:

SELECT * FROM products
WHERE
  CASE
    WHEN category = 'Электроника' THEN price < 50000
    WHEN category = 'Одежда'      THEN price < 5000
    ELSE price < 10000
  END;

Это эквивалентно сложному условию с OR, но иногда CASE делает логику нагляднее.

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

1. Забытый END:

SELECT CASE WHEN price > 1000 THEN 'дорогой'
            ELSE 'дешёвый'
      -- нет END!
FROM products;  -- синтаксическая ошибка

CASE ... END — обязательная пара, как открывающая и закрывающая скобки.

2. Нет ELSE — результат NULL:

SELECT CASE
         WHEN status = 'active' THEN 'Активен'
         WHEN status = 'banned' THEN 'Заблокирован'
       END AS status_label
-- Если status = 'pending' — вернёт NULL
-- Добавьте ELSE:
       END AS status_label
-- ELSE 'Другой' END

3. Порядок условий важен:

CASE
  WHEN score >= 50 THEN 'Сдал'      -- проверяется первым
  WHEN score >= 90 THEN 'Отлично'   -- никогда не достигается для >= 90!
END
-- Правильно: сначала более узкие условия
CASE
  WHEN score >= 90 THEN 'Отлично'
  WHEN score >= 50 THEN 'Сдал'
  ELSE 'Не сдал'
END

Практический пример: сегментация клиентов

Задача: разделить клиентов на сегменты по количеству заказов:

SELECT customer_id,
       name,
       order_count,
       CASE
         WHEN order_count = 0              THEN 'Новый'
         WHEN order_count BETWEEN 1 AND 5  THEN 'Редкий'
         WHEN order_count BETWEEN 6 AND 20 THEN 'Постоянный'
         ELSE                                   'VIP'
       END AS customer_segment
FROM   customer_stats
ORDER BY order_count DESC;

Результат: каждый клиент получил сегмент — от «Нового» до «VIP». Это типичная аналитическая задача, где CASE WHEN незаменим.

CASE WHEN как инструмент трансформации данных

Одно из главных применений CASE WHEN — трансформация данных при выгрузке. База данных хранит данные в «технической» форме (коды, флаги, числа), а пользователи хотят видеть «человеческие» метки.

SELECT order_id,
       customer_name,
       CASE payment_method
         WHEN 1 THEN 'Карта'
         WHEN 2 THEN 'Наличные'
         WHEN 3 THEN 'СБП'
         WHEN 4 THEN 'Счёт'
         ELSE 'Неизвестно'
       END AS payment_label,
       CASE
         WHEN total_amount >= 10000 THEN 'Крупный'
         WHEN total_amount >= 1000  THEN 'Средний'
         ELSE 'Мелкий'
       END AS order_size,
       total_amount
FROM   orders
ORDER BY total_amount DESC;

Этот запрос делает выгрузку «человекочитаемой» без изменения данных в базе: метод оплаты отображается текстом, заказ получает метку размера.

CASE WHEN и NULL: полный пример

Обработка NULL-значений — одна из главных причин использовать CASE WHEN:

SELECT
  user_id,
  CASE
    WHEN last_login IS NULL                THEN 'Никогда не заходил'
    WHEN last_login < NOW() - INTERVAL '365 days' THEN 'Неактивен >1 года'
    WHEN last_login < NOW() - INTERVAL '30 days'  THEN 'Неактивен >30 дней'
    ELSE 'Активный'
  END AS activity_status
FROM users;

NOW() — текущий момент времени в PostgreSQL. INTERVAL — интервал времени. Детали работы с датами будут в модуле 9.

Возвращаемый тип CASE WHEN

Все ветки THENELSE) в одном CASE должны возвращать совместимые типы. Нельзя вернуть строку в одной ветке и число в другой без явного приведения типов:

-- Ошибка: несовместимые типы
CASE WHEN flag = 1 THEN 'да' ELSE 0 END  -- строка vs число

-- Правильно: один тип
CASE WHEN flag = 1 THEN 'да' ELSE 'нет' END
CASE WHEN flag = 1 THEN 1   ELSE 0      END

PostgreSQL пытается автоматически привести типы, если они совместимы, но лучше не полагаться на неявное преобразование.

Краткий итог

  • CASE WHEN условие THEN результат ... END — выражение с ветвлением
  • Условия проверяются сверху вниз; первое истинное — возвращает результат
  • ELSE — значение по умолчанию; без ELSE при несовпадении возвращается NULL
  • Короткая форма: CASE колонка WHEN значение THEN результат END — для проверок на равенство
  • CASE WHEN работает в SELECT, ORDER BY, WHERE и в агрегатных функциях
  • Порядок условий важен: ставьте более узкие условия выше более широких
  • Все ветки THEN/ELSE должны возвращать совместимые типы данных

Что дальше

Вы завершили четвёртый модуль — «Операторы и шаблоны». Вы освоили LIKE, IN, BETWEEN, IS NULL и CASE WHEN. В следующем модуле — агрегатные функции: COUNT, SUM, AVG, MIN, MAX и группировка данных с помощью GROUP BY. Это позволит делать не просто выборку строк, а вычислять итоговые показатели по группам данных.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике