Menu

Выражения CASE в SQLite: WHEN, THEN, ELSE и IIF

Как работает CASE в SQLite — простая и поисковая формы, использование в SELECT, ORDER BY и WHERE, и когда вместо CASE удобнее IIF.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

CASE — это if/else в SQL

CASE — это способ положить условную логику внутрь запроса. Он по очереди проходит по веткам WHEN, выбирает первую совпавшую и возвращает значение после THEN. Если ничего не совпало, возвращается значение из ELSE — или NULL, если ELSE вы не написали.

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

Вот и вся форма: CASE, одна или несколько WHEN ... THEN ..., опциональный ELSE, и потом END. END обязателен — забыть его — самая частая опечатка.

Реалистичный пример

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

Ветки проверяются сверху вниз. Побеждает первое совпадение, поэтому упорядочивайте их от самого узкого условия к самому общему. ELSE ловит всё, что не совпало с предыдущими ветками — без него 1200.00 вернулся бы как NULL вместо 'large'.

Поисковая форма против простой

Выше — поисковая форма: у каждой WHEN своё булево условие. Когда вы сравниваете одно выражение с несколькими константами, есть более короткая — простая — форма:

Выражение после CASE вычисляется один раз и сравнивается через = с каждым значением WHEN. Так чище, когда вы делаете лукапы по равенству на одном столбце.

Один нюанс: простой CASE использует =, а в SQL NULL = NULL — это не true. Если status может оказаться NULL, ветки 'A'/'B'/'C' его не поймают — и сработает ELSE. Чтобы обработать NULL явно, переключайтесь на поисковую форму и пишите WHEN status IS NULL THEN ....

CASE в ORDER BY

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

По алфавиту получается 'high' < 'low' < 'medium', что для триажа бесполезно. Сопоставление каждого приоритета числу через CASE даёт тот порядок, который вам реально нужен. Хвостовое , id стабильно ломает ничьи.

CASE в WHERE

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

Распродажные товары проходят при цене ниже 20, обычные — ниже 30. Сам порог условный. Без CASE пришлось бы писать (on_sale = 1 AND price < 20) OR (on_sale = 0 AND price < 30) — тот же результат, только шумнее.

CASE внутри агрегатов

Вот где CASE по-настоящему окупается. Скомбинируйте его с SUM или COUNT, и вы за один проход посчитаете итоги по подмножеству строк — SQL-эквивалент «посчитай, сколько из этих подходят»:

CASE возвращает 1 на совпавших строках и 0 на остальных, поэтому SUM превращается в условный счётчик. Тот же приём работает и для выручки — на нужных строках возвращайте total, а на остальных 0. Один проход по таблице — несколько условных агрегатов сразу.

IIF: короткая форма для двух веток

Для одного условия с двумя исходами в SQLite есть IIF(cond, when_true, when_false). Это чистая короткая запись для CASE WHEN cond THEN when_true ELSE when_false END:

Берите IIF, когда логика бинарная и так читается лучше в одну строку. К CASE переходите, как только появляется три и более ветки, нужно отдельно обработать NULL или хочется ясный порядок проваливания через несколько WHEN.

Грабли, которые стоит знать

Вещи, на которые регулярно наступают:

  • Забыли END. CASE открывает блок; END его закрывает. SQLite даст ошибку парсинга где-то заметно позже самой ошибки.
  • Без ELSE будет NULL. Если ни одна WHEN не совпала, а ELSE вы пропустили, результат — NULL. Иногда это и нужно, но обычно — нет.
  • Порядок веток важен. В поисковой форме побеждает первая совпавшая WHEN. Поставите WHEN total < 500 раньше WHEN total < 100 — и до второй ветки выполнение никогда не дойдёт.
  • Смесь типов. Каждая ветка может вернуть свой тип, и SQLite на это не пожалуется — но дальше по конвейеру такой код легко ломает другую логику. Старайтесь, чтобы ветки возвращали совместимые типы (все текст, все числа).
  • Простой CASE и NULL. Как уже говорили: простая форма использует =, который никогда не совпадает с NULL. Если NULL-ы в игре — переходите на поисковую форму.

Дальше: строковые функции

CASE помогает ветвиться по значениям; следующая глава — про преобразование значений. Строковые функции — UPPER, LOWER, SUBSTR, REPLACE, шаблоны LIKE — закрывают повседневную работу с очисткой и переформатированием текстовых столбцов. С них и начнём.

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

Что такое выражение CASE в SQLite?

Выражение CASE — это SQL-эквивалент if/else: проверяет условия и возвращает значение. Это именно выражение, а не оператор, поэтому ставить его можно везде, где допустимо значение: в SELECT, WHERE, ORDER BY, UPDATE, и даже внутри агрегатов. Каждая ветка выглядит как WHEN условие THEN значение, плюс необязательный ELSE в конце.

В чём разница между простым и поисковым CASE в SQLite?

Простой CASE сравнивает одно выражение с несколькими значениями: CASE status WHEN 'A' THEN ... WHEN 'B' THEN ... END. Поисковый CASE в каждой ветке считает свой булев предикат: CASE WHEN price > 100 THEN ... WHEN qty = 0 THEN ... END. Поисковая форма гибче — в ней свободно смешиваются столбцы, операторы и проверки на NULL.

Когда в SQLite брать IIF вместо CASE?

IIF(cond, a, b) — это короткая запись для CASE WHEN cond THEN a ELSE b END. Берите IIF, когда логика двухветочная и так читается чище. К CASE имеет смысл переходить, как только веток становится три и больше, нужен порядок проваливания или явная обработка NULL через WHEN col IS NULL.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ