SQL CASE WHEN: условная логика в запросах
Урок 3.5 · Время чтения: ~7 мин · Задачи для практики ↓
Выражение CASE в SQL добавляет в запрос логику «если - то - иначе»: оно проверяет условия по порядку и возвращает значение первого истинного. В этом уроке вы изучите две формы CASE, научитесь создавать категории и метки в SELECT, сортировать по собственному приоритету и использовать CASE в WHERE.
Функции из предыдущих уроков преобразуют каждую строку одинаково. Но часто правило зависит от данных: платёж меньше $2 - «маленький», больше $6 - «крупный»; аренда без даты возврата - «не возвращена». CASE позволяет записать такие правила прямо в SQL, не перенося их в код приложения.
Синтаксис CASE
У CASE две формы.
Поисковый CASE
Каждая ветка WHEN содержит собственное условие. Это более гибкая и самая распространённая форма:
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE default_result
END
Простой CASE
Одно выражение сравнивается со списком значений:
CASE expression
WHEN value1 THEN result1
WHEN value2 THEN result2
ELSE default_result
END
Как вычисляется CASE
- Условия проверяются сверху вниз.
- Возвращается результат первого истинного условия; остальные уже не проверяются.
- Если ни одно условие не истинно, возвращается значение из
ELSE. - Если
ELSEнет, результат -NULL.
CASE - это выражение, а не отдельный оператор: оно возвращает одно значение и может стоять везде, где допустимо значение, - в SELECT, WHERE или ORDER BY.
CASE в SELECT: категории и метки
Уровни платежей
SELECT payment_id,
amount,
CASE
WHEN amount < 2 THEN 'Low'
WHEN amount < 6 THEN 'Medium'
ELSE 'High'
END AS payment_level
FROM payment
LIMIT 10;
Результат: десять платежей, у каждого уровень: меньше $2 - «Low», от $2 до $6 - «Medium», от $6 и выше - «High».
Порядок условий важен. Платёж в $1 удовлетворяет и условию amount < 6, но получает «Low», потому что побеждает первая подходящая ветка. Благодаря этому второму условию не нужна нижняя граница.
Понятный статус
SELECT rental_id,
rental_date,
CASE
WHEN return_date IS NULL THEN 'Not returned'
ELSE 'Returned'
END AS rental_status
FROM rental
ORDER BY rental_date DESC
LIMIT 10;
Результат: последние аренды с текстовым статусом вместо пустой или заполненной даты возврата.
Простой CASE для кодов
Простая форма удобна, когда в столбце хранятся коды:
SELECT title,
rating,
CASE rating
WHEN 'G' THEN 'General audiences'
WHEN 'PG' THEN 'Parental guidance'
WHEN 'PG-13' THEN 'Parents strongly cautioned'
WHEN 'R' THEN 'Restricted'
ELSE 'Adults only'
END AS rating_description
FROM film
LIMIT 10;
Результат: фильмы с понятным описанием их рейтинга.
CASE в ORDER BY: собственный порядок сортировки
Алфавитный порядок кодов рейтинга (G, NC-17, PG, PG-13, R) не совпадает с их смыслом. CASE превращает каждый код в число-приоритет:
SELECT title, rating
FROM film
ORDER BY CASE rating
WHEN 'G' THEN 1
WHEN 'PG' THEN 2
WHEN 'PG-13' THEN 3
WHEN 'R' THEN 4
ELSE 5
END,
title;
Результат: фильмы от самого мягкого рейтинга к самому строгому; внутри рейтинга - по названию.
Тот же приём поднимает наверх важные строки:
SELECT rental_id, rental_date, return_date
FROM rental
ORDER BY CASE WHEN return_date IS NULL THEN 0 ELSE 1 END,
rental_date DESC
LIMIT 20;
Результат: сначала невозвращённые аренды, затем остальные; в каждой группе новые - первыми.
CASE в WHERE
CASE может вернуть значение для условия, например порог, зависящий от другого столбца:
SELECT payment_id, staff_id, amount
FROM payment
WHERE amount >= CASE
WHEN staff_id = 1 THEN 5
ELSE 3
END
LIMIT 10;
Результат: платежи не меньше $5 для сотрудника 1 и не меньше $3 для остальных.
Большинство таких фильтров можно записать и через AND и OR: WHERE (staff_id = 1 AND amount >= 5) OR (staff_id <> 1 AND amount >= 3). Выбирайте вариант, который легче читается: для двух веток часто это OR, для многих - CASE.
Практические советы
- Всегда пишите
ELSE. Без него неожиданные значения превращаются вNULL, и такие строки легко пропустить. - Возвращайте один тип данных. Смешивание текста и чисел в разных ветках ведёт к неявным преобразованиям и сюрпризам.
- Располагайте условия от частных к общим. Побеждает первая истинная ветка.
- В уроке 4.4 вы будете использовать
CASEвнутри агрегатных функций, чтобы одним запросом считать строки по категориям.
Ключевые выводы:
CASEвозвращает результат первого истинного условияWHENилиELSE, если ни одно не истинно.- Поисковый
CASEпроверяет любые условия; простойCASEсравнивает одно выражение со значениями. - Без
ELSEрезультат -NULL. - В
SELECTCASEсоздаёт категории и понятные метки. - В
ORDER BYон задаёт собственный порядок сортировки, а вWHEREможет сделать фильтр зависимым от других столбцов.
Часто задаваемые вопросы
Чем отличаются простой CASE и поисковый CASE?
Простой CASE сравнивает одно выражение со списком значений: CASE rating WHEN 'G' THEN .... Поисковый CASE проверяет отдельное условие в каждой ветке: CASE WHEN amount < 2 THEN .... Поисковый CASE умеет всё, что простой, а также диапазоны, проверки на NULL и условия по нескольким столбцам.
Что вернёт CASE, если ни одно условие не истинно и ELSE нет?
NULL. Чтобы избежать сюрпризов, всегда добавляйте ветку ELSE с явным значением по умолчанию.
Есть ли в SQL функция IF?
Стандартный способ - CASE. В MySQL и MariaDB есть также IF(condition, value_if_true, value_if_false), а в SQL Server - IIF(), но они не переносимы.