Условная агрегация используется, когда требуется агрегировать значения (например, сумму или количество) по различным условиям в рамках одного запроса. Исторически, для достижения подобных целей SQL-разработчикам приходилось писать множественные подзапросы или делать джойны и группировки отдельно по каждой категории, что вело к менее читаемому и менее производительному коду.
Проблема заключалась в трудности одновременного вычисления нескольких агрегатов с разными условиями — каждый отдельный агрегат обычно требует фильтрации, и простое применение SUM() или COUNT() не учитывает нужное условие внутри агрегатной функции.
Решение — использование конструкции CASE внутри агрегатной функции, что позволяет "разделять" агрегаты по разным условиям на лету, не прибегая к множественным объединениям:
Пример кода:
SELECT department, SUM(CASE WHEN status = 'approved' THEN amount ELSE 0 END) AS approved_sum, SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS pending_sum, COUNT(CASE WHEN status = 'rejected' THEN 1 END) AS rejected_count FROM payments GROUP BY department;
Ключевые особенности:
Можно ли обойтись без конструкции CASE для условной агрегации?
Некорректный ответ — использовать WHERE в запросе напрямую вместе с агрегатной функцией. На самом деле WHERE фильтрует строки до агрегации, а не внутри каждой агрегатной колонки.
Пример кода (неверный способ):
SELECT COUNT(*) FROM payments WHERE status = 'approved'; SELECT COUNT(*) FROM payments WHERE status = 'pending';
Эти запросы нельзя склеить в одну строку результата по разным условиям без CASE.
Что произойдет, если использовать NULL внутри условного выражения?
Если CASE не возвращает альтернативное значение, то по умолчанию оно будет NULL, а агрегатная функция будет игнорировать NULL.
Пример кода:
SUM(CASE WHEN status = 'approved' THEN amount END) -- Если статус не 'approved', то NULL, и строка игнорируется в SUM
Можно ли использовать IF вместо CASE?
В некоторых диалектах SQL (например, MySQL) это возможно, но такой код становится непереносимым между разными базами данных. В универсальных запросах всегда применяйте CASE.
Аналитик попытался посчитать суммы по каждому статусу, написав несколько отдельных подзапросов. Внешний отчет стал сложным, добавление новых статусов потребовало переписывания кода каждый раз.
Плюсы:
Разработчик использовал CASE в одном общем запросе, сделав универсальный отчет с возможностью расширения под новые статусы через простой edit одного запроса.
Плюсы: