SQLLab
Все статьи

CASE WHEN в SQL: условная логика в запросах

Как использовать CASE WHEN в SQL: простой и поисковый вариант, применение в SELECT, GROUP BY, ORDER BY и агрегатных функциях. Примеры на реальных данных.

5 марта 2026 г.·4 мин чтения·

CASE WHEN — это if/else в SQL. Позволяет добавить условную логику прямо в запрос: создавать новые столбцы, категоризировать данные, делать сводные таблицы.

Два варианта синтаксиса

Поисковый CASE (Search CASE)

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

Простой CASE (Simple CASE)

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

Простой CASE удобен когда проверяешь одно поле на равенство. Поисковый — для произвольных условий.

Примеры в SELECT

Категоризация

SELECT
    order_id,
    amount,
    CASE
        WHEN amount < 1000 THEN 'Маленький'
        WHEN amount < 10000 THEN 'Средний'
        ELSE 'Крупный'
    END AS order_size
FROM orders;

Перевод кодов в названия

SELECT
    user_id,
    CASE status
        WHEN 'A' THEN 'Активный'
        WHEN 'I' THEN 'Неактивный'
        WHEN 'B' THEN 'Заблокирован'
        ELSE 'Неизвестно'
    END AS status_name
FROM users;

Вычисление со скидкой

SELECT
    product_id,
    price,
    CASE
        WHEN is_vip_customer THEN price * 0.8
        WHEN price > 5000 THEN price * 0.9
        ELSE price
    END AS final_price
FROM cart_items;

CASE в агрегатных функциях

Это мощный паттерн — считать разные вещи в одном запросе.

Условный COUNT

SELECT
    city,
    COUNT(*) AS total_orders,
    COUNT(CASE WHEN status = 'completed' THEN 1 END) AS completed,
    COUNT(CASE WHEN status = 'cancelled' THEN 1 END) AS cancelled
FROM orders
GROUP BY city;

Для продвинутых: в PostgreSQL есть более лаконичный синтаксис через FILTER:

COUNT(*) FILTER (WHERE status = 'completed') AS completed

В MySQL можно использовать SUM(status = 'completed') (булево автоматически приводится к 0/1). Но вариант с CASE — самый универсальный и понятный везде.

Условная сумма (pivot)

SELECT
    DATE_TRUNC('month', created_at) AS month,
    SUM(CASE WHEN category = 'Electronics' THEN amount ELSE 0 END) AS electronics,
    SUM(CASE WHEN category = 'Clothing' THEN amount ELSE 0 END) AS clothing,
    SUM(CASE WHEN category = 'Food' THEN amount ELSE 0 END) AS food
FROM orders
GROUP BY 1
ORDER BY 1;

Этот приём называют pivot или «разворот таблицы»: значения из столбца category (Electronics, Clothing, Food) превращаются в отдельные колонки результата. В некоторых СУБД есть специальный оператор PIVOT, но CASE + SUM — универсальный способ, который работает везде.

CASE в ORDER BY

SELECT name, status, priority
FROM tasks
ORDER BY
    CASE status
        WHEN 'urgent' THEN 1
        WHEN 'high' THEN 2
        WHEN 'normal' THEN 3
        ELSE 4
    END,
    created_at;

Полезно когда нужен нестандартный порядок сортировки.

CASE в GROUP BY

SELECT
    CASE
        WHEN age < 18 THEN 'До 18'
        WHEN age < 30 THEN '18–29'
        WHEN age < 45 THEN '30–44'
        ELSE '45+'
    END AS age_group,
    COUNT(*) AS users_cnt,
    AVG(purchase_amount) AS avg_purchase
FROM users
GROUP BY 1
ORDER BY 1;

Совет по оптимизации: CASE в GROUP BY или ORDER BY вычисляется для каждой строки, и оптимизатор не может использовать обычный индекс по исходному столбцу. Если такая группировка нужна часто — подумайте о добавлении отдельного столбца-категории в таблицу и заполнении его на стороне приложения или триггером.

CASE vs COALESCE vs NULLIF

-- COALESCE — более короткий способ заменить NULL
COALESCE(phone, 'Не указан')
-- эквивалентно:
CASE WHEN phone IS NOT NULL THEN phone ELSE 'Не указан' END

-- NULLIF — возвращает NULL если значения равны (защита от деления на 0)
amount / NULLIF(quantity, 0)
-- эквивалентно:
amount / CASE WHEN quantity = 0 THEN NULL ELSE quantity END

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

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

-- ❌ Неправильно: первое условие перехватит всё
CASE
    WHEN salary > 0 THEN 'Есть зарплата'
    WHEN salary > 100000 THEN 'Высокая'  -- никогда не выполнится
END

-- ✅ Правильно: от частного к общему
CASE
    WHEN salary > 100000 THEN 'Высокая'
    WHEN salary > 0 THEN 'Есть зарплата'
    ELSE 'Нет данных'
END

CASE в WHERE — антипаттерн

Частая ошибка — писать CASE в WHERE для условной фильтрации:

-- ❌ Так делать не надо
WHERE CASE WHEN department = 'IT' THEN salary > 100000 ELSE salary > 50000 END

Это мешает оптимизатору использовать индексы. Перепишите через AND/OR:

-- ✅ Лучше и быстрее
WHERE (department = 'IT' AND salary > 100000)
   OR (department != 'IT' AND salary > 50000)

ELSE по умолчанию возвращает NULL

Если ни одно условие не сработало и ELSE не указан — результат NULL. Всегда добавляй ELSE если это важно.

Итого

CASE WHEN используется:

  • В SELECT — для вычисляемых столбцов и категоризации
  • Внутри COUNT(), SUM() — для условной агрегации и pivot
  • В ORDER BY — для нестандартной сортировки
  • В GROUP BY — для группировки по вычисляемым категориям

Похожие статьи

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

Тренажёр с реальными задачами — бесплатно и без регистрации

Открыть тренажёр →