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— для группировки по вычисляемым категориям