Оператор CASE в предложении GROUP BY

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

SELECT
    CASE
        WHEN ram < 64
        THEN 'W95'
        WHEN ram < 128
        THEN 'W98'
        ELSE 'W2k'
    END Type,
    COUNT(*) Qty
FROM PC
GROUP BY
    CASE
        WHEN ram < 64
        THEN 'W95'
        WHEN ram < 128
        THEN 'W98'
        ELSE 'W2k'
    END;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]

В результате выполнения запроса получим:

TypeQty
W2k6
W953
W983

Здесь мы дублируем оператор CASE в предложении SELECT, чтобы получить столбец с наименованием операционной системы.

Использование оператора CASE в предложении GROUP BY позволяет в рамках одного запроса выполнять группировку по разному числу столбцов. Рассмотрим, например, следующую задачу.

Для каждой комбинации скорости процессора и объема жесткого диска определить среднюю цену ПК. Для ПК со скоростью процессора менее 600 выполнять группировку только по скорости процессора.

Сначала для сравнения приведем результаты группировки по одному (speed) и двум столбцам (speed, hd) соответственно.

select speed,max(hd) max_hd, avg(price) avg_price
from pc
group by speed;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]
speedmax_hdavg_price
45010350
50010487.5
60014850
75020900
80020970
90040980
select speed, hd max_hd, avg(price) avg_price
from pc
group by speed, hd
order by speed;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]
speedmax_hdavg_price
4508350
45010350
5005600
50010375
6008850
60014850
75014850
75020950
80020970
90040980

Поскольку в каждой группе значения hd совпадают, можно max(hd) и hd использовать равноправно.

Теперь дадим решение нашей задачи:

select speed, max(hd) max_hd, avg(price) avg_price
from pc
group by speed, 
         case 
             when speed >= 600 
             then hd 
             else speed 
         end
order by speed;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]
speedmax_hdavg_price
45010350
50010487.5
6008850
60014850
75014850
75020950
80020970
90040980

Когда speed >= 600, выполняется группировка по столбцам speed, hd. В противном случае группировка выглядит так:

GROUP BY speed, speed

что эквивалентно группировке одному столбцу. Кстати, оператор CASE в последнем решении можно было написать без ELSE:

select speed, max(hd) max_hd, avg(price) avg_price
from pc
group by speed, 
         case 
             when speed >= 600 
             then hd 
         end
order by speed;
🚫
[[ error ]]
[[ column ]]
NULL [[ value ]]

Хотя явная группировка - GROUP BY speed, NULL - будет вызывать ошибку.