Медиаблог /

CASE WHEN в SQL: условная логика, синтаксис и примеры для всех СУБД

17 сентября 2026

CASE WHEN в SQL: условная логика, синтаксис и примеры для всех СУБД

CASE WHEN — оператор условной логики SQL, закреплённый в стандарте ANSI SQL-92 и аналог конструкции if/else в процедурных языках — Python, Java, JavaScript. Он не изменяет данные в таблице, а возвращает одно из нескольких значений в зависимости от условий. Конструкция case when обязательно завершается END и работает в шести контекстах: SELECT, ORDER BY, GROUP BY, HAVING, WHERE и UPDATE. Поддерживается в PostgreSQL, MySQL, SQL Server, Oracle и SQLite без изменений. В статье — две синтаксических формы, примеры кода для каждого контекста и нюансы конкретных СУБД.

Монитор с синтаксисом CASE WHEN в тёмном редакторе SQL-кода

Что такое CASE WHEN в SQL

CASE WHEN — выражение, которое проверяет последовательность условий и возвращает значение первого сработавшего. Это не процедура и не функция: конструкция встраивается прямо в запрос и создаёт вычисляемое значение в результирующем наборе, не изменяя данные в таблице.

image

Учитесь бесплатно за счёт государства

Экономия до 100 000 ₽ на любой программе

Выбрать курс

По смыслу условный оператор CASE повторяет if/else из Python или Java и switch/case из JavaScript: перебирает условия сверху вниз, останавливается на первом совпадении, возвращает соответствующее значение. Если ни одна ветка не сработала и ELSE не задан — возвращает NULL.

Зачем это нужно? Вместо того чтобы тянуть сырые коды статусов на уровень приложения и переводить их там, логику категоризации, замены и фильтрации держат прямо в SQL. Аналитические отчёты, сегментация пользователей, разметка воронки — всё строится через условную логику в одном запросе без дополнительных JOIN или подзапросов.

Синтаксис CASE WHEN: две формы

У конструкции case when sql две синтаксических формы. Обе завершаются обязательным END — пропуск этого ключевого слова даёт ошибку синтаксиса (syntax error), и это самый частый промах при первом знакомстве с оператором. Правило расстановки веток: строгие, узкие условия — первыми, широкие и общие — ниже.

Характеристика
Форма searched CASE
Форма simple CASE
Тип условий Произвольные булевы выражения Только точное равенство
Поддержка IS NULL
Поддержка диапазонов (≥, <)
AND/OR в одном WHEN
Применимость ~90% случаев Коды, статусы, фиксированные наборы

Searched CASE — произвольные условия

Форма с произвольными условиями (searched CASE) — самая гибкая:

CASE

WHEN условие_1 THEN результат_1

WHEN условие_2 THEN результат_2

ELSE результат_по_умолчанию

END

В каждом WHEN можно писать диапазоны, объединять несколько колонок через AND/OR, проверять на NULL через IS NULL. Пример — сегментация пользователей по сумме покупок:

SELECT

user_id,

CASE

WHEN total_spent >= 50000 THEN ‘platinum’

WHEN total_spent >= 10000 THEN ‘gold’

WHEN total_spent >= 2000 THEN ‘silver’

ELSE ‘bronze’

END AS tier

FROM users;

Условия проверяются сверху вниз; срабатывает первое совпавшее. ELSE задаёт значение по умолчанию — без него строки, не попавшие ни в одну ветку, получат NULL.

Simple CASE — сравнение с набором значений

Форма с фиксированным выражением (simple CASE) компактнее там, где нужно сравнить одну колонку с конкретными значениями:

CASE выражение

WHEN значение_1 THEN результат_1

WHEN значение_2 THEN результат_2

ELSE результат_по_умолчанию

END

Типичное применение — перевод кодов и статусов:

SELECT

order_id,

CASE status

WHEN ‘pending’ THEN ‘В ожидании’

WHEN ‘paid’ THEN ‘Оплачен’

WHEN ‘shipped’ THEN ‘Отправлен’

ELSE ‘Неизвестно’

END AS status_ru

FROM orders;

Ограничение: только точное равенство. IS NULL и диапазоны в этой форме не работают — для таких случаев используйте searched CASE.

Схема порядка проверки условий оператора CASE WHEN в SQL

CASE WHEN в разных контекстах SQL

Конструкция case when sql применима в шести контекстах: SELECT (создаёт вычисляемый столбец), ORDER BY (нестандартная сортировка), GROUP BY (группировка по вычисляемому признаку), HAVING (фильтрация групп), WHERE (ветвление по параметру) и UPDATE (массовое обновление по разным правилам).

CASE WHEN в SELECT

Самый частый паттерн — CASE WHEN в SELECT создаёт вычисляемую колонку «на лету», не трогая данные в таблице:

SELECT

user_id,

total_spent,

CASE

WHEN total_spent >= 50000 THEN ‘platinum’

WHEN total_spent >= 10000 THEN ‘gold’

WHEN total_spent >= 2000 THEN ‘silver’

ELSE ‘bronze’

END AS tier

FROM users;

Колонка tier существует только в результате запроса. Подходит для дашбордов, отчётов и промежуточных вычислений без изменения схемы таблицы.

CASE WHEN в ORDER BY и GROUP BY

В ORDER BY оператор задаёт нестандартный бизнес-порядок сортировки:

ORDER BY

CASE status

WHEN ‘paid’ THEN 1

WHEN ‘pending’ THEN 2

ELSE 3

END;

В GROUP BY возникает нюанс: MySQL и PostgreSQL позволяют группировать по алиасу из SELECT (GROUP BY tier), а SQL Server — нет. Универсальное решение — общее табличное выражение (CTE, Common Table Expression): вычислить CASE в WITH-блоке, затем группировать по алиасу из него.

CASE WHEN в WHERE и UPDATE

В WHERE конструкция нужна только при ветвлении логики по внешнему параметру — например, по роли пользователя. Простые фильтры лучше записывать через AND/OR: CASE в WHERE не позволяет базе задействовать индексы.

В UPDATE case when позволяет массово обновить строки по разным правилам за один проход:

UPDATE products

SET price = CASE

WHEN category = ‘premium’ THEN price * 1.10

WHEN category = ‘sale’ THEN price * 0.85

ELSE price

END;

CASE WHEN с агрегатными функциями

Условные агрегаты — ключевой аналитический паттерн: несколько метрик с разными условиями в одном запросе без дополнительных подзапросов и JOIN. Вместо нескольких отдельных SELECT достаточно одного с несколькими CASE WHEN внутри агрегатных функций.

Разобраться в SQL-аналитике глубже поможет программа «Специалист по аналитике и базам данных в информационных системах» на 72 часа — обучение проходит онлайн и бесплатно в рамках нацпроекта «Кадры». Подробнее — в каталоге программ обучения.

SUM + CASE WHEN — условная сумма

Паттерн: SUM агрегирует только те строки, где условие выполнено, остальные дают 0 через ELSE:

SELECT

DATE_TRUNC(‘month’, created_at) AS month,

SUM(CASE WHEN channel = ‘organic’ THEN amount ELSE 0 END) AS organic_revenue,

SUM(CASE WHEN channel = ‘paid’ THEN amount ELSE 0 END) AS paid_revenue

FROM orders

GROUP BY 1;

Выручка по каналам за каждый месяц — в одном запросе. Технически SUM игнорирует NULL, поэтому ELSE можно опустить. Но ELSE 0 делает намерение явным: читатель запроса сразу видит, что несовпавшие строки дают ноль, а не пустоту. Это хорошая практика читаемости.

COUNT + CASE WHEN — условный счётчик

Здесь ELSE специально не указывают: COUNT не считает NULL, поэтому строки без совпадения автоматически пропускаются:

SELECT

COUNT(*) AS registrations,

Хотите сменить профессию или повысить квалификацию?

Федеральный проект «Активные меры содействия занятости» даёт возможность пройти обучение бесплатно за счёт государства

  • Программы от ведущих вузов России — от 2 месяцев
  • Удостоверение или диплом установленного образца
  • Центр карьеры: 7 500+ вакансий, помощь с трудоустройством
Оставить заявку
image

COUNT(CASE WHEN onboarded_at IS NOT NULL THEN 1 END) AS onboarded,

COUNT(CASE WHEN first_order_at IS NOT NULL THEN 1 END) AS buyers,

COUNT(CASE WHEN first_order_at IS NOT NULL THEN 1 END) * 100.0

/ COUNT(*) AS conversion_pct

FROM users;

За один запрос получаем всю воронку: регистрации → онбординг → покупатели → процент конверсии.

Вложенный CASE и CTE

CASE можно вкладывать в THEN другого CASE. Один уровень вложенности читается нормально:

CASE

WHEN is_premium = 1 THEN

CASE WHEN total_spent >= 50000 THEN ‘Premium VIP’ ELSE ‘Premium’ END

ELSE ‘Free’

END AS segment

При двух уровнях и глубже код становится трудночитаемым и сложно поддерживаемым. Решение — общее табличное выражение (CTE): вычислить промежуточные значения в WITH-блоке, а в основном SELECT работать с алиасом без повторения всей конструкции:

WITH ranked AS (

SELECT

user_id,

CASE

WHEN total_spent >= 50000 THEN ‘platinum’

ELSE ‘bronze’

END AS tier

FROM users

)

SELECT tier, COUNT(*) FROM ranked GROUP BY tier;

Для сложных матриц условий альтернативный подход — справочная таблица с JOIN вместо глубокой вложенности.

CASE WHEN и NULL — главная ловушка

Антипаттерн, который не даёт предупреждений при выполнении запроса:

— Неправильно: всегда возвращает False

WHEN email = NULL THEN ‘пусто’

— Правильно

WHEN email IS NULL THEN ‘пусто’

NULL = NULL в SQL никогда не даёт True. Единственный способ проверить NULL — IS NULL / IS NOT NULL. Это правило распространяется на все ветки CASE без исключений.

Вторая ловушка: case when null — отсутствие ELSE. Если ни одна ветка не совпала, оператор вернёт NULL. В агрегатных функциях COUNT и SUM это работает в пользу разработчика — NULL игнорируется. В SELECT для дашборда — нежелательные пустые ячейки.

Для простой NULL-замены используйте COALESCE(x, 0) — это краткая запись CASE WHEN x IS NOT NULL THEN x ELSE 0 END. При сложной условной логике с несколькими ветками CASE остаётся предпочтительным.

CASE WHEN в разных СУБД

CASE WHEN входит в стандарт ANSI SQL и работает одинаково в любой реляционной базе данных. Различия — только в дополнительных возможностях: функции-сокращения, поддержка GROUP BY по алиасу и процедурный контекст.

Возможность
PostgreSQL
MySQL
MS SQL
Oracle
SQLite
CASE WHEN (ANSI)
FILTER (условный агрегат) ✅ (3.30+)
IF(cond, a, b)
IIF(cond, a, b)
GROUP BY по алиасу из SELECT

PostgreSQL — CASE WHEN и FILTER

PostgreSQL полностью поддерживает стандартный синтаксис, GROUP BY по алиасу допустим. Уникальная особенность — оператор FILTER для условных агрегатов:

SELECT

COUNT(*) FILTER (WHERE tier = ‘free’) AS free_users,

COUNT(*) FILTER (WHERE tier = ‘premium’) AS premium_users

FROM users;

FILTER читается компактнее SUM+CASE для простых условий. При сложной многоветочной логике CASE WHEN предпочтительнее — он переносим на другие СУБД.

MySQL — IF() как альтернатива

MySQL поддерживает CASE WHEN полностью, GROUP BY по алиасу допустим. Дополнительно доступна функция IF(условие, значение_если_истина, значение_если_ложь) для бинарного выбора:

SELECT IF(status = ‘paid’, ‘Оплачен’, ‘Не оплачен’) AS status_ru FROM orders;

IF() — не ANSI SQL, работает только в MySQL и ClickHouse. Для трёх и более условий используйте case when.

SQL Server (MS SQL) — IIF() и нюансы GROUP BY

MS SQL Server поддерживает CASE WHEN стандартно. Дополнительно доступен IIF(условие, значение_a, значение_b) — синтаксический сахар для двух веток:

SELECT IIF(total_spent >= 10000, ‘VIP’, ‘Standard’) AS segment FROM customers;

Важный нюанс: GROUP BY по алиасу из SELECT в MS SQL не работает. Дублируйте выражение в GROUP BY или применяйте общее табличное выражение (CTE).

Oracle — CASE в SQL и PL/SQL

В SQL-запросах Oracle поддерживает стандартный ANSI CASE без изменений. В процедурном языке Oracle — PL/SQL (Procedural Language/SQL) — CASE выступает самостоятельным оператором внутри блока DECLARE/BEGIN/END и завершается END CASE:

DECLARE

v_tier VARCHAR2(20);

BEGIN

CASE

WHEN :total_spent >= 50000 THEN v_tier := ‘platinum’;

WHEN :total_spent >= 10000 THEN v_tier := ‘gold’;

ELSE v_tier := ‘bronze’;

END CASE;

DBMS_OUTPUT.PUT_LINE(v_tier);

END;

Это единственная СУБД, где CASE используется вне SQL-запроса в процедурном контексте.

SQLite

SQLite поддерживает обе формы CASE WHEN в полном объёме. Применяется в мобильных приложениях, встраиваемых системах и прототипах, где нужна лёгкая база без серверной инфраструктуры.

Типичные ошибки с CASE WHEN

Шесть антипаттернов, с которыми сталкиваются даже опытные разработчики:

  1. Забыть END — запрос падает с ошибкой синтаксиса. END обязателен всегда.
  2. WHEN col = NULL вместо IS NULL — условие никогда не выполнится; NULL не равен ничему, включая самого себя.
  3. Широкое условие раньше узкого — WHEN total_spent >= 1000 перехватит всех platinum/gold/silver, если стоит первым. Строгие условия — наверх.
  4. Смешивание несовместимых типов — текст в одной ветке и число в другой дают ошибку типизации в большинстве СУБД.
  5. Глубокий вложенный CASE — три уровня и глубже трудно читать и отлаживать; выносите промежуточные вычисления в CTE.
  6. Дублирование CASE в GROUP BY без CTE — в MS SQL и Oracle алиас из SELECT недоступен в GROUP BY; копировать длинное выражение вручную опасно и неудобно.

Шесть типичных ошибок при использовании CASE WHEN в SQL

CASE WHEN и альтернативы — что выбрать

Конструкция
Что делает
Когда выбрать
СУБД
CASE WHEN … END Условная логика с N ветками Основной инструмент Все
COALESCE(x, default) Первое не-NULL значение из списка Простая NULL-замена Все
NULLIF(a, b) NULL если a равно b Защита от деления на ноль Все
IF(cond, a, b) Бинарное условие, 2 ветки Быстрая проверка MySQL, ClickHouse
IIF(cond, a, b) Бинарное условие, 2 ветки Быстрая проверка SQL Server
COUNT(*) FILTER (WHERE …) Условный агрегат Компактные агрегаты в PostgreSQL PostgreSQL, SQLite 3.30+

COALESCE и NULLIF — узкоспециализированные инструменты для работы с NULL и делением. IF/IIF закрывают бинарную логику в конкретных СУБД. CASE WHEN — универсальный инструмент для любой условной логики с двумя и более ветками, переносимый между всеми основными базами данных без изменений.

Часто задаваемые вопросы

Что вернёт CASE WHEN, если не указать ELSE и ни одно условие не сработало?

Вернёт NULL. В агрегатных функциях COUNT и SUM это нормально — NULL игнорируется автоматически. В SELECT для дашборда или отчёта нежелательно: добавьте ELSE с запасным значением, чтобы избежать пустых ячеек.

Можно ли вложить CASE внутрь CASE?

Да, вложенность синтаксически допустима. Оптимальная глубина — один уровень. При двух уровнях и более вынесите промежуточные вычисления в общее табличное выражение (CTE) через WITH — это улучшит читаемость и упростит отладку.

Чем IIF() в SQL Server отличается от CASE WHEN?

IIF(cond, a, b) — сокращение для CASE WHEN cond THEN a ELSE b END. Поддерживает только две ветки и доступен исключительно в SQL Server. Для трёх и более условий используйте полный синтаксис case when.

Когда стоит использовать COALESCE вместо CASE?

Когда нужна только простая NULL-замена: COALESCE(x, 0) короче и читаемее. При сложной условной логике — несколько условий, разные значения, диапазоны — CASE WHEN остаётся предпочтительным.

Влияет ли CASE WHEN на производительность запроса?

В большинстве контекстов — нет. Исключение: CASE в предикате WHERE блокирует использование индексов. Заменяйте обычными условиями AND/OR; CASE в WHERE оправдан только при ветвлении логики по внешнему параметру — например, по роли пользователя.

Можно ли использовать CASE WHEN в WHERE?

Синтаксически — да. Но CASE в WHERE не позволяет базе данных задействовать индексы и усложняет план запроса. Используйте только при необходимости ветвить саму логику условия в зависимости от параметра, а не для обычной фильтрации.

Почему GROUP BY с CASE нужно писать дважды?

GROUP BY вычисляется раньше SELECT — алиас из SELECT в этот момент ещё неизвестен ядру базы. PostgreSQL и MySQL допускают GROUP BY по алиасу напрямую; MS SQL и Oracle — нет. Универсальное решение: вычислить CASE в общем табличном выражении (CTE) и группировать по алиасу из него.

Чем FILTER в PostgreSQL лучше SUM(CASE WHEN)?

COUNT(*) FILTER (WHERE cond) компактнее и чище читается. Но FILTER доступен только в PostgreSQL и SQLite начиная с версии 3.30. SUM(CASE WHEN … ELSE 0 END) переносимо: работает в MySQL, MS SQL и Oracle. Выбирайте FILTER для PostgreSQL-проектов, CASE — для кросс-СУБД кода.

Подайте заявку —
забронируйте место в группе

45 000 мест на 2026 год. Бесплатное обучение по федеральному проекту «Активные меры содействия занятости»

  • Онлайн
  • От 2 месяцев
  • Бесплатно
  • Диплом
Учиться бесплатно
icon