TablePlus
How to count unique rows in MySQL with COUNT DISTINCT?
Overview
In MySQL, COUNT() function returns the number of rows in a table.
COUNT(DISTINCT expression) returns the number of rows that contain non NULL values as the result of the specified expression.
Syntax
To to use COUNT(DISTINCT) in a SELECT statement:
Example
We have table sales :
| item | customer_name |
|---|---|
| book | Alex |
| pen | Bob |
| book | Alex |
| book | Jim |
| shoes | Jim |
| pen | Bob |
| backpack | Bob |
| book | Bob |
| wallet | Alex |
| wallet | Alex |
| book | Bob |
| backpack | Jim |
Since a customer might have multiple purchases, the customer_name field has duplicate values. So to count the number of unique customers:
The result is 3.
A customer might purchased one item multiple times, to see how many unique items each customer already purchased, we can use GROUP BY :
| customer_name | unique_item |
|---|---|
| Alex | 2 |
| Bob | 3 |
| Jim | 3 |
We can also include WHERE to count the number of unique customers that bought the item book :
The result is 3.
Need a good GUI tool for databases? TablePlus provides a native client that allows you to access and manage Oracle, MySQL, SQL Server, PostgreSQL, and many other databases simultaneously using an intuitive and powerful graphical interface.
Как посчитать уникальные значения в sql

Используем DISTINCT и COUNT() . Первый удалит дубликаты, а вторая посчитает количество строк.
Рекомендуемые курсы
Похожие вопросы
- О нас
- Карьера в Хекслете
- Хекслет Колледж
- Условия использования
- Соглашение об обработке ПД
- Оферта
- Акции
- 8 800 100 22 47 бесплатно по РФ
- +7 495 085 28 38 бесплатно по Москве
- support@hexlet.io
ООО «Хекслет Рус» 432071, г. Ульяновск, пр-т Нариманова, дом 1Г, оф. 23 ОГРН 1217300010476
Подсчет уникальных значений
Есть таблица org (name, emp_id). Для каждого возможного значения name , необходимо вывести количество уникальных emp_id . Можно ли это сделать с помощью count() или как ещё?
UPD: Немного расшифрую. Допустим
В результате необходимо получить что-то вроде
т.е. если emp_id повторяется в разных name , то их необходимо подсчитывать
Первая интерпретация вашего вопроса Для каждого name подсчитать уникальное количество emp_id
Вторая интерпретация, подсчитать так, что бы исключить emp_id встречающиеся у разных name Для этого пойдем от обратного подсчитаем количество name у emp_id , то есть нам необходимо исключить из выборки emp_id встречающиеся у нескольких name
SQL HowTo: считаем «уников» на интервале
Для систем управления бизнесом часто приходится решать очень похожий класс задач по вычислению количества уникальных объектов на произвольном временном интервале. В контексте CRM это могут быть «пользователи, обращавшиеся на горячую линию на прошлой неделе«, «контрагенты, оплатившие за последние 30 дней» или «потенциальные клиенты, с кем был контакт в этом квартале«.
Искать в большом количестве фактов «уники» — всегда сложно и долго, если их достаточно много. Если интервалы фиксированы (календарные месяц/квартал/год), можно материализовывать такие агрегаты заранее. А если интервал — произвольный, как тогда эффективно найти ответ?

Сначала смоделируем ситуацию, как она выглядит для нас, в масштабах «Тензора» — 5000 наших сотрудников до 100 000 раз за сутки общаются с потенциальными клиентами или с кем-то из уже работающих с нами 5 миллионов пользователей:
А теперь попробуем ответить на простой вопрос — сколько было уникальных клиентов в декабре?
Понятно, что если вся «первичка» уже лежит в PostgreSQL, то для реализации одной лишь этой функции выгружать данные во внешнюю СУБД с колоночным хранением данных вроде ClickHouse, которая подошла бы именно для этой задачи лучше, не особо оправданно с точки зрения эксплуатации разнородной архитектуры.
Получилось чуть больше 1364K «уников» из 1594K «фактов», но считалось это как-то слишком долго — 717мс [explain.tensor.ru]:

«Наивный» подсчет по первичным данным
Но самое печальное — это объем данных, который нам приходится прочитать — почти 23K страниц, то есть примерно 180MB. И если любая из них окажется не в кэше, и ее придется вычитывать с диска — тормоза нам обеспечены.
ARRAY
Но мы можем попробовать заранее «упаковать» имеющиеся у нас данные, чтобы в момент запроса читать самый минимум — использовать массив уникальных идентификаторов за каждый день (ведь нам заранее неизвестен интервал, который захочет запросить пользователь):
Тогда нам останется лишь прочитать записи за нужный интервал дней, «развернуть» все идентификаторы и посчитать количество уникальных:
Читать приходится в 26 раз меньше — всего 888 страниц, да и по времени отыграли 10% — до 642мс [explain.tensor.ru]:

Группировка массивов
hstore
Но в варианте с массивом нам пришлось каждый из них unnest ‘ить и уникализировать самостоятельно? Но ведь есть способ отдать уникализацию самому серверу — использовать сложение hstore с одноименными ключами:
Не забываем, что сначала необходимо установить это расширение в свою базу:
И только после этого пакуем, не забывая, что все ключи должны быть текстовыми:
Теперь нам необходимо «сложить» hstore -объекты в нужных строках, но соответствующей агрегатной функции hstore_agg не существует. Не беда — создадим ее сами:
Воспользуемся функцией akeys , которая вернет нам массив ключей собранного объекта:
Читать теперь приходится в 2.5 раза больше — 3049 страниц, зато по времени — еще минус 5% — 612мс [explain.tensor.ru]:

Группировка hstore
jsonb
Но ведь есть «нативный» тип, который самостоятельно делает уникализацию ключей — json[b]:
Давайте обойдемся без всех этих дополнительно устанавливаемых расширений:
Правда, агрегатную функцию снова придется делать самим:
И даже не будем пробовать извлекать ключи — достаточно уже агрегации.
. чтобы понять, что хоть jsonb и гораздо компактнее hstore (читать приходится лишь чуть больше, чем для массивов — 963 страницы), но это не окупает адских тормозов при агрегации почти на 13 секунд! [explain.tensor.ru]:

Группировка jsonb
Итак, в сегодняшнем забеге упаковка в массив позволяет получить наиболее сбалансированный по объему и скорости результат.
А еще быстрее — можно? Да, но это уже материал для хаба «ненормальное программирование».
Основные затраты времени у нас шли на объединение массивов/объектов. То есть чем меньше записей с «пакетами» нам необходимо обработать — тем лучше.
Для этого все даты можно покрыть отрезками длиной 2^N :

Сегментация дат
Тогда любой из заданных пользователем интервалов можно разбить на такие непересекающиеся отрезки:

Разбиение интервала на сегменты
Ну, а каскадное добавление ID клиента во все такие отрезки можно с помощью несложной функции: