Если несколько условий CASE истинны одновременно, какая ветвь определит результат?
Результат определит первая истинная ветвь WHEN, то есть та, которая записана выше остальных. Последующие условия для выбора результата уже не меняют ответ; если истинных условий нет, используется ELSE, а при его отсутствии результатом обычно будет NULL.
Условное выражение CASE появилось как декларативный способ выполнять разветвление непосредственно в SQL-запросе. Оно решает задачу вычисления значения для каждой строки без перехода к процедурному коду или отдельным запросам для разных случаев.
Порядок ветвей позволяет явно задать приоритет правил: более специфичное условие размещают раньше общего. Поэтому перестановка одинаковых по смыслу условий может изменить результат запроса.
Перекрывающиеся условия встречаются, например, при классификации заказов, расчёте тарифов или присвоении категорий. Ошибка в порядке WHEN может незаметно отнести строку к более общей категории, хотя она подходит под специальное правило.
Особенно опасно полагаться на порядок вычисления отдельных выражений внутри условий как на способ избежать ошибки деления, обращения к недопустимому значению или другой проблемы. Порядок выбора ветвей определён, но оптимизатор конкретной СУБД может иметь собственные правила вычисления подвыражений.
CASE проверяет условия WHEN последовательно сверху вниз. При первом результате TRUE выбирается соответствующее выражение THEN, а остальные ветви не участвуют в выборе результата.
Платёж на 1500 подходит сразу под оба первых условия, но результатом будет крупный, поскольку это первая совпавшая ветвь. Если поставить условие amount >= 100 выше, все платежи от 100 и больше попадут в категорию обычный, и ветвь amount >= 1000 фактически станет недостижимой.
Ветка ELSE необязательна. При отсутствии совпадения и ELSE результат CASE равен NULL, что может повлиять на сортировку, фильтрацию, арифметику и последующую агрегацию.
Важно различать логический выбор ветви и физический порядок вычисления выражений. Нельзя универсально использовать CASE как гарантию безопасного вычисления любого опасного подвыражения: константные выражения, план оптимизации и особенности СУБД могут привести к более раннему вычислению части выражения.
Практическое правило: размещайте частные условия перед общими, делайте ветви взаимоисключающими, если это возможно, и явно задавайте ELSE. Это повышает читаемость и уменьшает риск неявного NULL.
В отчёте нужно разделить клиентов на категории: VIP для оборота от 1 000 000, крупных для оборота от 100 000 и остальных. Рассматривались два варианта: сначала проверять общее условие «от 100 000» или сначала специальное условие VIP.
Первый вариант короче на вид, но неверен: каждый VIP также удовлетворяет условию крупного клиента и будет классифицирован как крупный. Второй вариант проверяет VIP первым, затем крупного клиента и в конце использует ELSE для остальных.
Выбран второй вариант, потому что порядок отражает приоритет бизнес-правил. В результате категории не перекрываются по фактическому результату, а добавление ELSE не оставляет необработанные значения без явного объяснения.
Что произойдёт, если ни одна ветвь WHEN не истинна и ELSE отсутствует?
CASE вернёт NULL. Это может быть незаметно: например, COUNT(выражения) не посчитает такие значения, а сравнение результата с обычным значением не станет TRUE из-за трёхзначной логики SQL.
Можно ли считать все последующие WHEN гарантированно невычисляемыми после первого совпадения?
Для выбора результата CASE используется первая истинная ветвь, но это не означает абсолютную гарантию физического порядка вычисления каждого подвыражения. Оптимизатор может заранее обработать некоторые константные или неизбежные выражения. Поэтому CASE не следует рассматривать как универсальный механизм защиты от любых ошибок вычисления.
Почему условие ELSE обычно стоит задавать явно даже при полном, на первый взгляд, покрытии случаев?
Требования к данным могут измениться, появиться NULL или значение вне ожидаемого диапазона. Явный ELSE фиксирует поведение для таких строк: он может вернуть отдельную категорию, NULL или другое диагностически полезное значение. Это лучше, чем полагаться на неявный NULL, который может исказить отчёт без явного сигнала об ошибке.