Условие
Таблица fb_active_users(user_id, name, status, country). status ∈ {open, closed}. Посчитайте долю пользователей, у которых одновременно status = 'open' И country = 'USA', к общему числу пользователей.
Округлить до 2 знаков, в виде доли (0.xx).
Решение
SELECT
ROUND(
SUM(CASE WHEN status = 'open' AND country = 'USA' THEN 1 ELSE 0 END)::DECIMAL
/ COUNT(*),
2
) AS active_us_share
FROM fb_active_users;Или через AVG
SELECT
ROUND(AVG(CASE WHEN status = 'open' AND country = 'USA' THEN 1.0 ELSE 0 END), 2)
AS active_us_share
FROM fb_active_users;В Postgres/MySQL оба работают. В Oracle для AVG с булевыми CASE нужно 1 или 0 (как число), и 1.0 форсирует numeric.
Почему не «двойной» подзапрос
Соблазн: (SELECT COUNT(*) WHERE ... = 'open' AND country = 'USA') / (SELECT COUNT(*) FROM ...). Работает, но медленнее (два прохода) и int / int — обрезание. Условный SUM/AVG — один проход.
Подводные камни
int / int.SUM(CASE...)без::DECIMALдаст 0 (если результат < 1). Классика SQL-боли.statusмог быть NULL. Не попадёт ни в числитель, ни в знаменатель (если делатьWHERE status IS NOT NULL). Решите по бизнес-смыслу: NULL — это «активные неизвестно?»; обычно нет.AND country = 'USA'. Если кейс — «или США, или активные» (OR), формула другая. Внимательно читаем условие.
Эталонный ответ
ROUND(SUM(CASE WHEN status='open' AND country='USA' THEN 1 ELSE 0 END)::DECIMAL / COUNT(*), 2). Однопроходный запрос.