Перейти к содержанию

CASE в PostgreSQL - подробная шпаргалка

CASE - одно из самых универсальных и недооценённых выражений в PostgreSQL.  

С его помощью можно реализовывать условную логику прямо внутри SQL: без процедур, без IF, без лишних JOIN.

В PostgreSQL существует два синтаксических варианта CASE:

  1. CASE с выражением (simple CASE)
  2. CASE без выражения (searched CASE)

Они похожи внешне, но решают разные задачи.


1. CASE с выражением (simple CASE)

Синтаксис

CASE <expression>
    WHEN <value_1> THEN <result_1>
    WHEN <value_2> THEN <result_2>
    ...
    ELSE <default_result>
END

Пример:

CASE status
    WHEN 'new' THEN 'Новый'
    WHEN 'in_progress' THEN 'В работе'
    WHEN 'done' THEN 'Завершён'
    ELSE 'Неизвестно'
END

Как это работает

  • <expression> вычисляется один раз
  • каждый WHEN - это проверка на равенство

Фактически PostgreSQL делает примерно следующее:

status = 'new'
status = 'in_progress'
status = 'done'


Когда использовать simple CASE

✔️ Маппинг значений ✔️ Статусы ✔️ Коды, типы, категории ✔️ Справочники

Пример из практики:

CASE order_type
    WHEN 1 THEN 'Розница'
    WHEN 2 THEN 'Опт'
    WHEN 3 THEN 'Подписка'
END


2. CASE без выражения (searched CASE)

Синтаксис

CASE
    WHEN <condition_1> THEN <result_1>
    WHEN <condition_2> THEN <result_2>
    ...
    ELSE <default_result>
END

Пример

CASE
    WHEN amount < 0 THEN 'Отрицательное'
    WHEN amount = 0 THEN 'Ноль'
    WHEN amount > 0 THEN 'Положительное'
    ELSE 'Ошибка'
END

Как это работает

  • каждый WHEN - логическое выражение
  • условия могут быть любой сложности

Допустимо всё:

> < >= <=
IN / NOT IN
LIKE / ILIKE
ISNULL
EXISTS (subquery)
AND / OR / NOT


Когда использовать searched CASE

✔️ Диапазоны значений ✔️ Сложные бизнес-правила ✔️ Несколько колонок в условии ✔️ Комбинированная логика ✔️ Аналитические запросы

Пример:

CASE
    WHEN amount > 1000 AND region = 'EU' THEN 'Крупный заказ'
    WHEN amount > 500 THEN 'Средний заказ'
    ELSE 'Малый заказ'
END


3. Частая ошибка новичков ❌

Попытка использовать условие в simple CASE:

CASE amount
    WHEN amount > 100 THEN 'Большое'
END

Это не сработает, потому что: * WHEN ожидает значение, а не условие * фактически это читается как:

amount = (amount > 100)

Правильный вариант ✔️

CASE
    WHEN amount > 100 THEN 'Большое'
END

4. CASE всегда возвращает одно значение

CASE - это выражение, а не оператор управления потоком.

❗ Он обязан вернуть одно значение для строки.

SELECT
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        ELSE 'C'
    END AS grade
FROM exams;

5. Тип результата CASE

Тип результата определяется по всем THEN и ELSE.

CASE
    WHEN condition THEN 1
    ELSE 0
END
➡ тип: integer


❌ Ошибка типов:

CASE
    WHEN condition THEN 1
    ELSE 'нет'
END

PostgreSQL попытается привести типы → ошибка

✔️ Решение - явное приведение:

CASE
    WHEN condition THEN '1'
    ELSE 'нет'
END
или
CASE
    WHEN condition THEN 1
    ELSE NULL
END


6. ELSE необязателен (но опасен)

CASE
    WHEN amount > 0 THEN 'Плюс'
END

Если ни одно условие не сработает → вернётся NULL. 💡 Рекомендация: Всегда явно писать ELSE, если NULL не является ожидаемым результатом.


7. Порядок WHEN имеет значение ❗

Проверка идёт сверху вниз. Как только найдено первое совпадение - CASE завершается.

❌ Ошибка:

CASE
    WHEN amount > 0 THEN 'Положительное'
    WHEN amount > 100 THEN 'Большое'
END

amount > 100 никогда не выполнится.

✔️ Правильно:

CASE
    WHEN amount > 100 THEN 'Большое'
    WHEN amount > 0 THEN 'Положительное'
END


8. CASE внутри агрегатных функций

Очень частый и мощный паттерн 💡

Условная агрегация

SUM(
    CASE
        WHEN status = 'done' THEN 1
        ELSE 0
    END
) AS done_count

или короче:

COUNT(*) FILTER (WHERE status = 'done')

Сумма по условию

SUM(
    CASE
        WHEN type = 'income' THEN amount
        ELSE 0
    END
)

9. CASE в WHERE и ORDER BY

В WHERE

WHERE
    CASE
        WHEN is_admin THEN true
        ELSE is_active
    END

В ORDER BY

ORDER BY
    CASE status
        WHEN 'urgent' THEN 1
        WHEN 'normal' THEN 2
        ELSE 3
    END

10. Практическая рекомендация

  • Используй CASE с выражением - для маппинга значений
  • Используй CASE без выражения - для логики и правил
  • Не бойся длинных CASE - они читаемее вложенных IF
  • Следи за типами
  • Помни про порядок WHEN

Краткое резюме

  • В PostgreSQL два разных CASE
  • Они решают разные задачи
  • Ошибки чаще всего связаны с выбором неправильного синтаксиса
  • CASE отлично работает с агрегатами и аналитикой
  • Это один из ключевых инструментов в SQL-мышлении

📌 Совет из практики Если логика начинает усложняться, почти всегда нужен CASE без выражения. simple CASE оставляй для чистого и аккуратного маппинга.