Задача
Вы хотите узнать, какие значения входят в набор данных, не перечисляя повторяющиеся значения многократно. Или хотите узнать, сколько уникальных значений входит в множество.
Решение
Используйте ключевое слово DISTINCT для выбора уникальных значений и конструкцию COUNT(DISTINCT) – для подсчета их количества.
Обсуждение
Удаление дубликатов для получения информации о том, какие значения или строки входят в набор данных, – это суммарная операция, не требующая использования агрегирующей функции. Используем ключевое слово DISTINCT (или его синоним DISTINCTROW). DISTINCT сокращает результат запроса и часто используется в сочетании с ORDER BY для расположения значений в более удобном порядке. Например, если вы хотите узнать имена водителей из таблицы driver_log, выполните такой запрос:
mysql> SELECT DISTINCT name FROM driver_log ORDER BY name;
+-------+
| name |
+-------+
| Ben |
| Henry |
| Suzi |
+-------+
Запрос без использования ключевого слова DISTINCT выводит те же самые имена, но в менее удобной форме:
mysql> SELECT name FROM driver_log;
+-------+
| name |
+-------+
| Ben |
| Suzi |
| Henry |
| Henry |
| Ben |
| Henry |
| Suzi |
| Henry |
| Ben |
| Henry |
+-------+
Если вы хотите узнать, сколько разных водителей включено в таблицу, используйте конструкцию COUNT(DISTINCT):
mysql> SELECT COUNT(DISTINCT name) FROM driver_log;
+------------------------------+
| COUNT(DISTINCT name) |
+------------------------------+
| 3 |
+------------------------------+
Конструкция COUNT(DISTINCT) игнорирует значения NULL. Если вы хотите сосчитать и значения NULL (если они присутствуют), сделайте следующее:
COUNT(DISTINCT знач) + IF(COUNT(IF(знач IS NULL,1,NULL))=0,0,1)
Того же эффекта можно достичь при помощи таких выражений:
COUNT(DISTINCT знач) + IF(SUM(ISNULL(знач))=0,0,1)
COUNT(DISTINCT знач) + (SUM(ISNULL(знач))!=0)
Конструкция COUNT(DISTINCT) доступна, начиная с MySQL версии 3.23.2. Если вы работаете с более ранней версией, необходимо использовать какой-то обходной маневр для вычисления количества строк запроса SELECT DISTINCT.
Можно, например, выбрать уникальные значения в отдельную таблицу, а затем применить COUNT(*) для подсчета количества строк новой таблицы.
Запросы DISTINCT часто используются в сочетании с агрегирующими функциями для получения более полного описания имеющихся данных. Например, если применить COUNT(*) к таблице customer, вы узнаете количество своих клиентов, применив DISTINCT к значениям таблицы state, вы узнаете,в каких штатах живут ваши клиенты. Если же выполнить COUNT(DISTINCT) к значениям state, то будет выведено количество штатов, в которых есть ваши клиенты.
Если использовать DISTINCT для нескольких столбцов, то будут выведены уникальные комбинации значений этих столбцов, а COUNT(DISTINCT) вычислит количество таких комбинаций. Следующий запрос находит в таблице mail различные пары отправитель-получатель (srcuser-dstuser) и считает иколичество:
mysql> SELECT DISTINCT srcuser, dstuser FROM mail
-> ORDER BY srcuser, dstuser;
+---------+---------+
| srcuser | dstuser |
+---------+---------+
| barb | barb |
| barb | tricia |
| gene | barb |
| gene | gene |
| gene | tricia |
| phil | barb |
| phil | phil |
| phil | tricia |
| tricia | gene |
| tricia | phil |
+---------+---------+
mysql> SELECT COUNT(DISTINCT srcuser, dstuser) FROM mail;
+------------------------------------------+
| COUNT(DISTINCT srcuser, dstuser) |
+------------------------------------------+
| 10 |
+------------------------------------------+
Можно применять DISTINCT не только к столбцам, но и к выражениям. Чтобы вычислить количество часов дня, в которые отправлялись сообщения таблицы mail, будем учитывать неповторяющиеся значения HOUR():
mysql> SELECT COUNT(DISTINCT HOUR(t)) FROM mail;
+----------------------------------+
| COUNT(DISTINCT HOUR(t)) |
+----------------------------------+
| 12 |
+----------------------------------+
Чтобы узнать, какие именно это были часы, выведем их список:
mysql> SELECT DISTINCT HOUR(t) FROM mail ORDER BY 1;
+----------+
| HOUR(t) |
+----------+
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 17 |
| 22 |
| 23 |
+----------+
Обратите внимание на то, что запрос не сообщает нам, сколько сообщений было отправлено в каждый из часов.