MySQL / 7. Формирование итогов

Использование ключевого слова DISTINCT для удаления дубликатов

Задача
Вы хотите узнать, какие значения входят в набор данных, не перечисляя повторяющиеся значения многократно. Или хотите узнать, сколько уникальных значений входит в множество.

Решение
Используйте ключевое слово 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          |
+----------+

Обратите внимание на то, что запрос не сообщает нам, сколько сообщений было отправлено в каждый из часов.

Статьи по MySQL на эту тему:

Выбор групп только с определенными характеристиками
Группирование по результатам выражения
Итоги и значения NULL
Итоги по датам
Классификация некатегориальных данных

Вернуться в раздел: MySQL / 7. Формирование итогов