Условие
В таблице table хранятся связки клиентов и их типов: поле type принимает только 'a' или 'b'. Если клиент связан с обоими типами, считаем его типом 'a'.
Подсчитайте число уникальных клиентов в каждом типе.
client | type
1 | a
1 | b
1 | b
2 | b
3 | a
Ожидаемо: тип 'a' = 2 (клиент 1 «приоритетно a», клиент 3), тип 'b' = 1 (клиент 2).
Решение
Подход
- Для каждого клиента определить итоговый тип: если есть
'a'— это'a', иначе'b'. - Сгруппировать по этому итоговому типу.
SQL
WITH client_type AS (
SELECT
client,
CASE WHEN MAX(CASE WHEN type='a' THEN 1 ELSE 0 END) = 1 THEN 'a' ELSE 'b' END AS final_type
FROM table
GROUP BY client
)
SELECT final_type, COUNT(*) AS cnt
FROM client_type
GROUP BY final_type;Альтернатива через STRING_AGG или BOOL_OR
WITH ct AS (
SELECT
client,
CASE WHEN BOOL_OR(type='a') THEN 'a' ELSE 'b' END AS final_type
FROM table
GROUP BY client
)
SELECT final_type, COUNT(*) FROM ct GROUP BY final_type;Минимальная версия (без CTE)
SELECT
CASE WHEN BOOL_OR(type='a') THEN 'a' ELSE 'b' END AS final_type,
COUNT(DISTINCT client) AS cnt
FROM table
GROUP BY client
-- ... но тогда GROUP BY клиент, а COUNT — вне; см. CTE-версию выше как стандарт.Результат на примере
| final_type | cnt |
|---|---|
| a | 2 |
| b | 1 |
Подводные камни
- Если
typeможет приниматьNULL—BOOL_OR(type='a')корректно вернётFALSE, но клиент с однимNULLуйдёт в категорию'b'. Уточнить. - Если
typeможет содержать'A'(с регистром) — добавитьLOWER(type)='a'. - Не забывать
GROUP BY clientв первой стадии — иначеMAX/BOOL_ORагрегируют всю таблицу. - Версия с
EXISTS:WHERE EXISTS (SELECT 1 FROM table t2 WHERE t2.client=t.client AND t2.type='a')— тоже работает, но менее эффективно.
Эталонный ответ
На каждом клиенте BOOL_OR(type='a') → final_type; затем GROUP BY final_type, COUNT(*). Клиент с обоими типами уходит в 'a'.