Как посчитать COUNT DISTINCT в SQL
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Базовый синтаксис
SELECT COUNT(DISTINCT column) FROM TABLE;1. Уникальные пользователи
SELECT COUNT(DISTINCT user_id) AS unique_users
FROM events;2. По комбинации колонок
-- уникальные пары (user_id, product_id)
SELECT COUNT(DISTINCT user_id, product_id) FROM orders; -- MySQL
-- Postgres (другой синтаксис)
SELECT COUNT(DISTINCT (user_id, product_id)) FROM orders;
-- универсально — concat или CTE
SELECT COUNT(DISTINCT user_id || '|' || product_id) FROM orders;3. Уникальные по условию
SELECT
COUNT(DISTINCT CASE WHEN status = 'paid' THEN user_id END) AS paying_users,
COUNT(DISTINCT CASE WHEN status = 'free' THEN user_id END) AS free_users
FROM users;4. Уникальные по группам
SELECT
category,
COUNT(DISTINCT user_id) AS unique_users
FROM orders
GROUP BY category;5. DAU / MAU через COUNT DISTINCT
-- DAU
SELECT DATE(event_at) AS day, COUNT(DISTINCT user_id) AS dau
FROM events
GROUP BY 1;
-- MAU (скользящие 30 дней)
SELECT COUNT(DISTINCT user_id) AS mau
FROM events
WHERE event_at >= NOW() - INTERVAL '30 days';6. Approximate count distinct (для больших данных)
Точный COUNT DISTINCT требует просмотра всех значений → медленно.
Алгоритм HyperLogLog (HLL) даёт приблизительный ответ с погрешностью ~1% за O(1) памяти.
ClickHouse
-- точно
SELECT COUNT(DISTINCT user_id) FROM events;
-- быстро (примерно)
SELECT uniq(user_id) FROM events;
-- ещё быстрее, ещё менее точно
SELECT uniqHLL12(user_id) FROM events;BigQuery
SELECT APPROX_COUNT_DISTINCT(user_id) FROM events;Snowflake
SELECT APPROX_COUNT_DISTINCT(user_id) FROM events;Postgres
Нет встроенного. Через extension postgresql-hll.
7. COUNT(DISTINCT) vs COUNT(*)
SELECT
COUNT(*) AS total_events, -- все события
COUNT(DISTINCT user_id) AS unique_users -- уникальные пользователи
FROM events;Если у одного user 10 events — total = 10, unique = 1.
8. COUNT(*) vs COUNT(column)
COUNT(*) -- все строки, включая NULL
COUNT(column) -- только строки, где column IS NOT NULL
COUNT(DISTINCT col) -- уникальные не-NULL значения9. Уникальные с фильтром даты
SELECT COUNT(DISTINCT user_id)
FROM events
WHERE event_at >= '2026-01-01'
AND event_at < '2026-02-01';10. Динамика уникальных по дням
SELECT
DATE(event_at) AS day,
COUNT(DISTINCT user_id) AS daily_unique_users,
SUM(COUNT(DISTINCT user_id)) OVER (ORDER BY DATE(event_at)) AS cumulative
FROM events
GROUP BY 1;Внимание: cumulative через SUM не совпадёт с total unique (разные метрики).
11. Уникальные X за каждые Y
-- дневная DAU в каждом месяце
SELECT
DATE_TRUNC('month', event_at) AS month,
DATE(event_at) AS day,
COUNT(DISTINCT user_id) AS dau
FROM events
GROUP BY 1, 2;12. Проблема COUNT DISTINCT на миллиардах
-- медленно на больших данных
SELECT COUNT(DISTINCT user_id) FROM events; -- может занять часы
-- быстрее через approximate
SELECT uniq(user_id) FROM events; -- секундыДля аналитики ±1% обычно ок.
13. В оконных функциях
-- нестандарт, не везде работает
COUNT(DISTINCT user_id) OVER (PARTITION BY category)
-- обычно обходят через CTE
WITH per_category AS (
SELECT category, COUNT(DISTINCT user_id) AS uniq
FROM orders
GROUP BY category
)
SELECT o.*, pc.uniq
FROM orders o
JOIN per_category pc ON pc.category = o.category;Частые ошибки
1. COUNT(*) когда нужен DISTINCT
-- неправильно: считает строки, не пользователей
SELECT COUNT(*) FROM events;
-- правильно
SELECT COUNT(DISTINCT user_id) FROM events;2. DISTINCT внутри группировки
-- не то, что думаете
SELECT category, COUNT(DISTINCT *) FROM orders GROUP BY category; -- invalid
-- правильно
SELECT category, COUNT(DISTINCT user_id) FROM orders GROUP BY category;3. NULL в DISTINCT
COUNT DISTINCT игнорирует NULL. Если нужны NULL в счёте:
COUNT(DISTINCT COALESCE(col, 'missing'))4. Смешивать COUNT и SUM
COUNT считает строки / non-null. SUM суммирует значения. Разные вещи.
Связанные темы
FAQ
COUNT DISTINCT медленный — что делать?
Approximate count (uniq в ClickHouse, APPROX_COUNT_DISTINCT в BigQuery/Snowflake). Или партиционирование.
Точный или приблизительный?
Для аналитики с миллионами записей ±1% обычно ок. Approximate в 10-100 раз быстрее.
DISTINCT нужен в group by?
Нет. GROUP BY уже группирует по уникальным значениям.
NULL считается в COUNT DISTINCT?
Нет, NULL игнорируется. Для включения — COALESCE.
Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.