Оператор SQL CASE WHEN: синтаксис, реальные примеры и распространенные ошибки

  1. Главная
  2. Блог
  3. Базы данных и SQL

Базы данных и SQL

Инструкция SQL CASE WHEN: Синтаксис, реальные примеры и распространенные ошибки

CASE WHEN — это то, как вы пишете логику «если-то» в SQL. Изучите обе формы, а затем используйте их для меток, сводных отчетов, пользовательской сортировки и безопасных обновлений, избегая при этом NULL и ловушек упорядочивания.

8 мин чтения
Оператор SQL CASE WHEN: синтаксис, реальные примеры и распространенные ошибки

Главное

  • CASE возвращает значение на основе истинного условия first.
  • Сначала поставьте наиболее конкретные условия, иначе более поздние могут никогда не быть достигнуты.
  • Если ELSE нет, несовпадающие строки возвращают NULL.
  • Внутри SUM или COUNT CASE превращает один запрос в компактный сводный отчет.

Большинству отчетов нужна определенная логика: помечайте заказы как большие или маленькие, подсчитывайте оплаченные и ожидающие заказы рядом или сначала отображайте срочные товары. SQL CASE WHEN обрабатывает все это непосредственно внутри запроса и работает во всех основных базах данных.

Мы выполнили каждый запрос здесь, в SQLite 3.50, и показанные результаты получены в результате этого запуска. CASE является частью стандартного SQL, поэтому в этих примерах он ведет себя одинаково в PostgreSQL, MySQL, SQL Server и Oracle.

Что такое СЛУЧАЙ КОГДА?

CASE — это выражение, а не отдельная команда. Он оценивает условия по порядку и возвращает значение, поэтому его можно использовать везде, где разрешено значение: в SELECT, WHERE, GROUP BY, ORDER BY или внутри функций. Он всегда заканчивается на END.

CASE
  WHEN condition1 THEN result1
  WHEN condition2 THEN result2
  ELSE fallback
END

Пример таблицы

CREATE TABLE orders (id INT, customer TEXT, total INT, status TEXT);

INSERT INTO orders VALUES
 (1,'Asha',1200,'paid'), (2,'Ben',300,'pending'),
 (3,'Asha',800,'paid'), (4,'Chitra',2500,'shipped'),
 (5,'Dev',150,'cancelled'), (6,'Ben',NULL,'pending');

Обратите внимание, что в заказе 6 нет суммы. Этот ряд имеет значение позже.

Поиск ДЕЛА

Это более гибкая форма, поскольку каждый WHEN имеет собственное полное условие:

SELECT id, total,
       CASE
         WHEN total >= 1000 THEN 'large'
         WHEN total >= 500 THEN 'medium'
         ELSE 'small'
       END AS size
FROM orders;

-- 1 | 1200 | large
-- 2 |  300 | small
-- 3 |  800 | medium
-- 4 | 2500 | large
-- 5 |  150 | small
-- 6 | NULL | small

Посмотрите на последний ряд. В заказе 6 нет общей суммы, но он помечен как «маленький». Оба сравнения с NULL были неверны, поэтому оно провалилось в ELSE. Мы покажем, как это исправить, в разделе NULL. Всегда присваивайте результату имя, используя AS, иначе вы можете получить неудобное имя столбца.

Простой СЛУЧАЙ

Когда вы сравниваете один столбец с фиксированными значениями, более короткая форма читается лучше:

SELECT id,
       CASE status
         WHEN 'paid' THEN 'Complete'
         WHEN 'shipped' THEN 'Complete'
         WHEN 'pending' THEN 'Waiting'
       END AS label
FROM orders;

-- 1 | Complete
-- 2 | Waiting
-- 3 | Complete
-- 4 | Complete
-- 5 | NULL
-- 6 | Waiting
Форма Сравнивает Можно ли использовать диапазоны? Лучшее для
Простой Одно выражение равенства Нет Сопоставление кодов с метками
Поиск Любое состояние по филиалу Да Диапазоны, несколько столбцов, проверки NULL

Порядок имеет значение

CASE останавливается при первом истинном условии, и это наиболее распространенная логическая ошибка. Поменяйте местами два условия из нашего предыдущего запроса:

SELECT id, total,
       CASE
         WHEN total >= 500 THEN 'medium'
         WHEN total >= 1000 THEN 'large'
         ELSE 'small'
       END AS size
FROM orders WHERE id IN (1, 4);

-- 1 | 1200 | medium
-- 4 | 2500 | medium

Теперь ничто не может быть «большим». Общее число 2500 также составляет не менее 500, поэтому первая ветвь выигрывает, а вторая никогда не достигается. Никаких ошибок не появляется, только неправильные метки. Для диапазонов сначала укажите наиболее ограничительное условие или запишите полные диапазоны, например total >= 500 AND total < 1000.

Что происходит без ELSE?

В нашем простом примере CASE выше заказ 5 был отменен, и ни одна ветвь не обработала его, поэтому результатом было NULL. Иногда это именно то, что вам нужно, как показано в следующем разделе. Но при создании меток обычно лучше использовать чистый ELSE 'other', поскольку он делает неожиданные значения видимыми, а не оставляет пробелы в отчете.

Совет. Все ветки должны возвращать один и тот же тип. Смешивание текста и чисел в SQLite работает слабо, но более строгие базы данных, такие как PostgreSQL, выдадут ошибку или попытаются преобразовать значения способами, которые вы не планировали.

Сводные отчеты с SUM

Это один из наиболее полезных шаблонов в повседневном SQL. Обертывание CASE в агрегат превращает строки в столбцы, по одной строке на каждого клиента:

SELECT customer,
       SUM(CASE WHEN status = 'paid' THEN total ELSE 0 END) AS paid,
       SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending_orders
FROM orders
GROUP BY customer
ORDER BY customer;

-- Asha   | 2000 | 0
-- Ben    |    0 | 2
-- Chitra |    0 | 0
-- Dev    |    0 | 0

Теперь один запрос дает как оплаченный доход, так и количество отложенных ордеров, без необходимости использования отдельных запросов или объединений. Этот шаблон работает практически в каждой базе данных, в отличие от специального синтаксиса PIVOT, который предлагают лишь некоторые. Если GROUP BY для вас новичок, прочтите SQL GROUP BY и HAVING.

Условные подсчеты

COUNT пропускает NULL, поэтому CASE без ELSE учитывает только соответствующие строки:

SELECT COUNT(*) AS all_orders,
       COUNT(CASE WHEN status = 'paid' THEN 1 END) AS paid_orders,
       COUNT(CASE WHEN total >= 1000 THEN 1 END) AS large_orders
FROM orders;

-- 6 | 2 | 2

Будьте осторожны: если вы добавите ELSE 0 внутрь COUNT, будет учитываться каждая строка, поскольку 0 не равен NULL. Используйте ELSE 0 с SUM и оставьте его с COUNT. PostgreSQL и SQLite также поддерживают COUNT(*) FILTER (WHERE ...), что хорошо читается, но доступно не везде.

Группировка по CASE

Вы можете создавать свои собственные сегменты, а затем суммировать их:

SELECT CASE WHEN total >= 1000 THEN 'large' ELSE 'other' END AS bucket,
       COUNT(*)
FROM orders
GROUP BY bucket
ORDER BY bucket;

-- large | 2
-- other | 4

Группировка по псевдониму работает в SQLite, PostgreSQL и MySQL. SQL Server не позволяет этого, поэтому вам придется повторить все выражение или сначала поместить запрос в CTE или подзапрос.

Пользовательская сортировка с помощью ORDER BY

Алфавитный порядок редко бывает тем, чего хочет бизнес. CASE позволяет вам определить свой собственный порядок:

SELECT id, status FROM orders
ORDER BY CASE status
           WHEN 'pending' THEN 1
           WHEN 'paid' THEN 2
           ELSE 3
         END, id;

-- 2 | pending
-- 6 | pending
-- 1 | paid
-- 3 | paid
-- 4 | shipped
-- 5 | cancelled

Отложенные ордера идут первыми, что удобно при рабочей очереди. Второй столбец сортировки, id, сохраняет строки в предсказуемом порядке внутри каждой группы.

ДЕЛО в ОБНОВЛЕНИИ

CASE позволяет одному оператору применять разные изменения к разным строкам. Здесь небольшие отложенные ордера помечены для проверки:

UPDATE orders
SET status = CASE
               WHEN status = 'pending' AND total < 500 THEN 'review'
               ELSE status
             END;

SELECT id, status FROM orders WHERE customer = 'Ben';

-- 2 | review
-- 6 | pending

ELSE status сохраняет другие строки без изменений. Не учитывать это опасно, поскольку несовпадающим строкам будет присвоено значение NULL. Без предложения WHERE этот оператор также затрагивает каждую строку, поэтому в больших таблицах добавьте фильтр и рассмотрите возможность переноса изменения в транзакцию, чтобы можно было проверить результат перед фиксацией. Обратите также внимание, что порядок 6 не изменился, поскольку его нулевая сумма не удовлетворяла total < 500.

НУЛЕВЫЕ ловушки

NULL вызывает две отдельные проблемы с CASE. Во-первых, простая форма сравнения использует равенство, и ничто не равно NULL, даже само NULL:

SELECT CASE NULL WHEN NULL THEN 'matched' ELSE 'not matched' END;

-- not matched

Итак, CASE col WHEN NULL никогда не совпадает. Вместо этого используйте форму поиска с помощью IS NULL. Во-вторых, как мы видели на примере порядка 6, значение NULL ускользает от сравнения и попадает в ELSE. Исправление состоит в том, чтобы сначала проверить это:

SELECT id,
       CASE
         WHEN total IS NULL THEN 'unknown'
         WHEN total >= 1000 THEN 'large'
         ELSE 'other'
       END AS size
FROM orders WHERE id IN (1, 2, 6);

-- 1 | large
-- 2 | other
-- 6 | unknown

Заказ 6 теперь получает честную маркировку. Наше руководство по значениям SQL NULL полностью описывает это поведение.

CASE против других вариантов

Вариант Работает в Используйте его, когда
ДЕЛО Все основные базы данных Вам нужна портативная логика
ОБЪЕДИНЯТЬСЯ Все основные базы данных Вам нужен только запасной вариант для NULL
IF() MySQL Простой двусторонний выбор
IIF() SQL-сервер, SQLite Простой двусторонний выбор
DECODE() Оракул Старый код Oracle
Таблица поиска Все Сопоставление длинное или часто меняется.

Последний вариант заслуживает размышления. Если CASE вырастет до тридцати ветвей и появится в пяти запросах, переместите сопоставление в таблицу и присоединитесь к ней. Тогда изменение — это обновление одной строки, а не изменение кода в пяти местах.

Распространенные ошибки

  • Неправильный порядок условий. Широкое условие сначала скрывает более узкие.
  • Забывание END. Это наиболее частая синтаксическая ошибка.
  • Использование WHEN NULL. Оно никогда не совпадает, поэтому используйте WHEN col IS NULL.
  • Добавление ELSE 0 внутрь COUNT. Подсчитывается все строки.
  • Пропуск ELSE в UPDATE. Он может стирать значения NULL.
  • Фильтрация по CASE в WHERE. Это может остановить использование индекса. См. наше руководство по оптимизации SQL-запросов.

Итоги

CASE WHEN — это небольшая функция, которая выполняет большую работу. Запомните три правила: побеждает первая истинная ветвь, несовпадающие строки становятся NULL без ELSE, а NULL требует собственной проверки. Для практики возьмите отчет, который вы сейчас создаете с помощью нескольких запросов, и попытайтесь создать его как один запрос, используя SUM(CASE ...).

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

Что делает CASE WHEN в SQL?

Он добавляет в запрос логику «если-то». SQL проверяет каждое условие по порядку и возвращает значение первого из них, которое является истинным, или значение ELSE, если оно не является истинным.

Что произойдет, если в операторе CASE нет ELSE?

Строки, не соответствующие ни одному условию, возвращают NULL. Это полезно внутри COUNT, но в метках и обновлениях это может привести к появлению пробелов или потере данных.

Могу ли я использовать CASE в предложении WHERE?

Да, потому что это выражение. Однако простые условия И и ИЛИ обычно более понятны, и в них с большей вероятностью будет использоваться индекс.

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

Simple CASE сравнивает одно выражение с фиксированными значениями на предмет равенства. Поисковый CASE имеет полное условие в каждом WHEN, поэтому он может обрабатывать диапазоны и проверки NULL.

Могут ли операторы CASE быть вложенными?

Да, один CASE может появиться внутри другого. Однако глубокую вложенность сложно читать, поэтому рассмотрите возможность объединения условий с помощью AND или использования таблицы поиска.

Продолжайте учиться

Работайте с Stack Quora

Нужна помощь с тестированием, WordPress или SEO?

Мы помогаем командам выпускать лучшее программное обеспечение и развивать свои сайты. Расскажите нам, над чем вы работаете, и мы предложим четкий следующий шаг.

Продолжайте читать

Больше руководств по тестирование, искусственный интеллект и современные разработки

Понравилась эта статья? Выберите тему и сразу приступайте к нашим новейшим руководствам.

Искусственный интеллект

Объяснение галлюцинаций искусственного интеллекта: почему языковые модели все выдумывают и как их уменьшить

Галлюцинации ИИ объяснили: что это такое, почему языковые модели их создают, распространенные типы, как уменьшить их с помощью заземления и подсказо…

Читать статью →
DevOps

Объяснение переменных среды: файлы .env, секреты и правильно выполненная конфигурация

Переменные среды объясняются на примерах Python, которые мы запускали: их чтение и установка, почему каждое значение является строкой, файлы .env, н…

Читать статью →
Разработка ПО

Объяснение ограничения скорости API: алгоритмы, заголовки и обработка ошибок 429

Ограничение скорости API объясняется с помощью проведенного нами моделирования: сегмент токенов, фиксированное окно, скользящее окно, 429 ответов, з…

Читать статью →
Автоматизация тестирования

Издевательство в Python: unittest.mock, патч и ошибки, из-за которых тесты лгут

Издевательство на Python с помощью unittest.mock, протестировано: Mock и return_value, Side_effect, исправление использования имени, спецификация и …

Читать статью →
Тестирование ПО

Объяснение покрытия кода: покрытие линий или ветвей и что на самом деле означает 100%

Покрытие кода объяснено с помощью реального запуска покрытия.py: покрытие строк, ветвей и условий, чтение отчета, почему 100%-ное покрытие все еще м…

Читать статью →
Базы данных и SQL

DELETE, TRUNCATE и DROP в SQL: различия, откат и когда использовать каждый из них

Объяснение DELETE, TRUNCATE и DROP на примере протестированного SQL: что каждый из них удаляет, откат, триггеры, сброс идентификаторов, скорость и ч…

Читать статью →
Базы данных и SQL

Объяснение представлений SQL: создавайте, используйте и избегайте ловушек, с примерами

Представления SQL, объясненные с помощью запросов, которые мы выполняли: создание представления, результаты в реальном времени, скрытие столбцов, пр…

Читать статью →
Разработка ПО

Интерфейс TypeScript и тип: реальные различия, протестированные с помощью компилятора

Интерфейс TypeScript против типа, проверенный реальным компилятором: что могут делать оба, что может делать только один, слияние объявлений, расшире…

Читать статью →
Разработка ПО

Объяснение Python *args и **kwargs: гибкие функции с понятными примерами

Python *args и **kwargs, объясненные с помощью кода, который мы запускали: упаковка и распаковка, порядок параметров, аргументы только по ключевым с…

Читать статью →
Разработка ПО

Лямбда-функции Python: синтаксис, реальное использование и когда их не следует использовать

Лямбда-функции Python, объясненные с помощью кода, который мы запускали: синтаксис, сортировка с помощью ключа, карты и фильтра, замыкания, ловушка …

Читать статью →
Искусственный интеллект

Что такое ИИ-агенты? Как они работают: можно запустить простой цикл агента

Что такое агенты ИИ? Простое руководство по циклу агента, инструментам, памяти и ограничениям, с небольшим циклом Python, который мы запустили, реал…

Читать статью →
DevOps

Мониторинг и наблюдаемость: реальная разница с журналами, метриками и трассировками

Объяснение мониторинга и наблюдаемости: известные и неизвестные сбои, журналы, метрики и трассировки, пошаговое руководство по инцидентам при оформл…

Читать статью →
DevOps

Docker Volumes против Bind Mounts: правильное сохранение данных контейнера

Объяснение томов Docker и монтирования привязки: почему исчезают данные контейнера, именованные тома, монтирование привязки, tmpfs, примеры создания…

Читать статью →
Автоматизация тестирования

TDD против BDD: ключевые различия, одна функция, созданная для обоих способов, и когда использовать каждый

TDD и BDD объясняются с помощью одной функции скидки, созданной в обоих направлениях: красно-зеленый рефакторинг с кодом, который мы запускали, сцен…

Читать статью →
Тестирование ПО

Пользовательское приемочное тестирование (UAT): процесс, контрольный список и реальные примеры

Приемочное тестирование пользователей объяснило: кто его проводит, чем оно отличается от контроля качества, семиэтапный процесс, шаблон тестового сц…

Читать статью →
Базы данных и SQL

Объяснение значений NULL в SQL: IS NULL, COALESCE, NULLIF и ловушки, которых следует избегать

Значения SQL NULL объяснены с помощью запросов, которые мы выполнили: трехзначная логика, IS NULL, COALESCE, NULLIF, как агрегаты, соединения и сорт…

Читать статью →
Базы данных и SQL

Оператор SQL CASE WHEN: синтаксис, реальные примеры и распространенные ошибки

SQL CASE WHEN объяснен с помощью запросов, которые мы выполняли: простые формы и формы для поиска, порядок условий, повороты с помощью SUM, трюки CO…

Читать статью →
Разработка ПО

Что такое JWT? Веб-токены JSON, объясненные на рабочем примере

Что такое JWT? Объяснение JSON Web Tokens: три части: токен, созданный и измененный в коде, который мы запускали, JWT и сеансы, хранилище, токены об…

Читать статью →
Разработка ПО

Объяснение цикла событий JavaScript: стек вызовов, микрозадачи и таймеры с примерами

Цикл событий JavaScript объясняется с помощью кода, который мы запускали: стек вызовов, очереди задач и микрозадач, почему setTimeout 0 не является …

Читать статью →
Разработка ПО

Генераторы Python и объяснение доходности: экономьте память с помощью реальных примеров

Генераторы Python и доходность, объясненные с помощью кода, который мы запускали: как они приостанавливаются и возобновляются, измеряют экономию пам…

Читать статью →
Искусственный интеллект

Что такое вложения? Простое объяснение векторов и косинусного сходства

Что такое вложения? Простое руководство по векторам, косинусному подобию и семантическому поиску с небольшим примером, который мы использовали, общи…

Читать статью →
DevOps

Сине-зеленое и канареечное развертывание: различия, компромиссы и как выбрать

Объяснение сине-зеленого и канареечного развертывания: как каждый из них работает, стоимость, риски и откат, стабильное группирование пользователей,…

Читать статью →
Автоматизация тестирования

Ненадежные тесты: что их вызывает и как их исправить навсегда

Ненадежные тесты объясняются на демонстрациях, которые мы запускали: основные причины, способы подтверждения и диагностики, правильные исправления в…

Читать статью →
Тестирование ПО

Нагрузочное тестирование и стресс-тестирование: различия, метрики и примеры k6

Объяснение нагрузочного и стресс-тестирования: что доказывает каждое из них, тесты на всплески и выдержки, важные метрики, почему средние значения в…

Читать статью →
Тестирование ПО

Тестовый пример и тестовый сценарий: ключевые различия, примеры и когда использовать каждый

Объяснение тестового случая и тестового сценария: четкие определения, параллельная таблица, одна функция сброса пароля, взятая из сценариев в случаи…

Читать статью →
Базы данных и SQL

Оптимизация SQL-запросов: чтение планов выполнения и исправление медленных запросов с указанием времени

Оптимизация SQL-запросов проверена на миллионе строк: читайте планы выполнения, добавляйте правильные индексы, исправляйте неразмещаемые фильтры, ис…

Читать статью →
Базы данных и SQL

SQL UNION против UNION ALL: различия, примеры и проверка производительности

SQL UNION и UNION ALL объяснены с помощью запросов, которые мы выполнили: дубликаты, правила, которым следуют оба, реальная ошибка данных, измеренна…

Читать статью →
Разработка ПО

Учебное пособие по API JavaScript Fetch: GET, POST, обработка ошибок и тайм-ауты

Учебное пособие по API JavaScript Fetch, протестированное на локальном сервере: GET и POST, почему не выдается ошибка 404, многоразовый помощник, ст…

Читать статью →
Разработка ПО

Обработка файлов Python: чтение, запись, CSV, JSON и pathlib с примерами

Обработка файлов Python объясняется с помощью кода, который мы запускали: открытые режимы, чтение больших файлов, CSV, JSON, pathlib, двоичные файлы…

Читать статью →
Разработка ПО

Классы и объекты Python: учебник ООП с реальными примерами

Классы и объекты Python, объясненные с помощью кода, который мы запускали: __init__, методы, атрибуты класса и экземпляра, наследование, свойства, м…

Читать статью →
Искусственный интеллект

Что такое большая языковая модель? Как работают LLM, объяснено без шумихи

Что такое большая языковая модель? LLM объясняется простым языком: токены, встраивания, внимание, обучение, температурные и контекстные окна, крошеч…

Читать статью →
DevOps

Команды Linux для начинающих: основное руководство по терминалу с примерами

Команды Linux для начинающих, сгруппированные по задачам: навигация, файлы, просмотр журналов, grep, каналы, разрешения, процессы и архивы, с практи…

Читать статью →
Автоматизация тестирования

Selenium vs Playwright: ключевые различия, сравнение кода и что выбрать

Сравнение Selenium и Playwright: архитектура, ожидание, поддержка браузера и языка, отладка, одинаковый тест в обоих инструментах, советы по миграци…

Читать статью →
Тестирование ПО

Разделение эквивалентности: метод проектирования тестов, объясненный на рабочих примерах

Объяснение эквивалентного разделения: как найти действительные и недействительные разделы, рабочие примеры для возрастов, паролей и купонов, проведе…

Читать статью →
Тестирование ПО

Серьезность и приоритет в тестировании программного обеспечения: различия, матрица и реальные примеры

Объяснение серьезности и приоритета при тестировании программного обеспечения: четкие определения, четырехсторонняя матрица с примерами, шкалы уровн…

Читать статью →
Базы данных и SQL

Учебное пособие по подзапросам SQL: типы, коррелирующие подзапросы и EXISTS с примерами

Руководство по подзапросам SQL с выполненными нами запросами: скалярные подзапросы, IN, FROM и SELECT, коррелированные подзапросы, EXISTS, ловушка N…

Читать статью →
Базы данных и SQL

Объяснение транзакций SQL и ACID: COMMIT, ROLLBACK и уровни изоляции

Транзакции SQL и ACID, объясненные с помощью банковского перевода, который мы выполнили: COMMIT, ROLLBACK, точки сохранения, блокировки, уровни изол…

Читать статью →
Разработка ПО

Git merge vs rebase: отличия, примеры и когда что использовать

Git merge vs rebase с реальным выводом log, сравнительной таблицей, золотым правилом rebase и безопасным рабочим процессом для команды.

Читать статью →
Разработка ПО

Генераторы списков в Python: синтаксис, примеры и когда их избегать

Генераторы списков в Python: синтаксис, фильтры, if-else, вложенные циклы, измеренное время и случаи, когда обычный цикл for лучше.

Читать статью →
Базы данных и SQL

SQL JOIN: объяснение с примерами (Inner, Left, Right, Full)

Разберите SQL JOIN шаг за шагом на примерах таблиц и запросов: INNER, LEFT, RIGHT, FULL, CROSS и SELF, а также частые ошибки и советы по производите…

Читать статью →