Короткий ответ
Можно посчитать два отдельных агрегата в одном SELECT, используя AVG(CASE WHEN status = 'delivered' THEN processing_time END) и аналогично для cancelled, без необходимости делать два отдельных запроса или GROUP BY status.
Как это работает подробнее
CASE внутри агрегатной функции возвращает значение только для строк, удовлетворяющих условию, а для остальных — NULL (если ELSE не задан); агрегатные функции (AVG, SUM, COUNT) по умолчанию игнорируют NULL, поэтому в расчёт попадают только нужные строки.
Пример кода
Запрос SQL
SELECT
AVG(CASE WHEN status = 'delivered' THEN processing_time END) AS avg_delivered,
AVG(CASE WHEN status = 'cancelled' THEN processing_time END) AS avg_cancelled
FROM orders;Что использовать на практике
- На практике: такой подход удобен, когда нужно вывести несколько «разрезов» метрики в одной строке результата — например, для сравнения в одной таблице отчёта, а не в нескольких строках после
GROUP BY status. В PostgreSQL для той же задачи есть более короткий синтаксисAVG(processing_time) FILTER (WHERE status = 'delivered'). - Результат: Результат — одна строка с двумя числами для сравнения.
- Проверка: сравнить
avg_deliveredс результатом отдельного запросаSELECT AVG(processing_time) FROM orders WHERE status = 'delivered'.
Подводные камни
- Частая ошибка: забывают, что
CASE WHEN ... THEN ... ENDбезELSEдаётNULL, а не0, из-за чего при использованииSUMвместоAVGрезультат может получиться верным случайно, а приAVG— наоборот, не учитывать несовпадающие строки в знаменателе, что и нужно, но иногда ожидания у аналитика другие.