SQL distinct: описание, примеры, свойства

Зачастую при использовании SQL для выборки информации из таблиц, пользователь получает избыточные данные, заключающиеся в наличии абсолютно идентичных повторяющихся строк. Для исключения этой ситуации используется аргумент SQL distinct в предложении Select. В данной статье будут рассмотрены примеры использования данного аргумента, а также ситуации, в которых от применения аргумента лучше отказаться.

Прежде чем мы приступим к рассмотрению конкретных примеров, создадим в базе данных пару необходимых таблиц.

Подготовка таблиц

Представим, что у нас в базе данных хранится информация об обоях, представленная в двух таблицах. Это таблица Oboi (обои) с полями id (уникальный идентификатор), type (тип обоев – бумажные, виниловые и др.), color (цвет), struct (структура) и price (цена). И таблица Ostatki (остатки) с полями id_oboi (ссылка на уникальный идентификатор в таблице Oboi) и count (количество рулонов на складе).

Заполним таблицы данными. В таблицу с обоями добавим 9 записей:

Oboi

id

type

color

struct

price

1

Бумажные

Мультиколор

Тисненые

56,9

2

Бумажные двухслойные

Беж

Гладкая

114,8

3

Виниловые

Оранж

Тисненые

504

4

Флизелиновые

Беж

Тисненые

1020,9

5

Бумажные двухслойные

Беж

Гладкая

150,6

6

Бумажные

Мультиколор

Гладкая

95,4

7

Виниловые

Коричневые

Гладкая

372

8

Флизелиновые

Белые

Тисненые

980,1

9

Тканевые

Розовые

Гладкая

1166,5

В таблицу с остатками – также девять записей:

Ostatki

id_oboi

count

1

8

2

12

3

24

4

9

5

16

6

7

7

24

8

32

9

11

Приступим к описанию порядка использования distinct в SQL.

Место distinct в предложении Select

Аргумент distinct следует помещать сразу после ключевого слова Select в запросах. Он применяется сразу ко всем столбцам, указанным в предложении Select, потому что будет исключать из итогового результата запроса абсолютно идентичные строки. Таким образом, достаточно один раз указать при написании запроса SQL «select distinct». Исключение составляет использование distinct внутри агрегатных функций, что рассмотрим чуть позднее.

Следует помнить, что большинство СУБД и не распознает ваш запрос вида:

SELECT distinct Ostatki.Count, distinct Oboi.*

FROM Oboi

INNER JOIN Ostatki ON Oboi.id = Ostatki.id_oboi

Здесь несколько раз указан рассматриваемый аргумент либо указан один раз, но перед вторым, третьим или иным выбираемым столбцом. Вы получите ошибку со ссылкой на неточности в синтаксисе.

Применение distinct в стандартных запросах

Очевидно, что при грамотном построении структуры таблиц и их заполнении, внутри одной таблицы исключены ситуации, когда встречаются абсолютно идентичные строки. Поэтому выполнение запроса «Select distinct *» с выборкой из одной таблицы практически нецелесообразно.

Представим ситуацию, когда нам необходимо узнать, какого типа есть у нас обои, сразу для удобства выполним сортировку по типу:

SELECT Oboi.type

FROM Oboi order by type

И получим результат:

type

Бумажные

Бумажные

Бумажные двухслойные

Бумажные двухслойные

Виниловые

Виниловые

Тканевые

Флизелиновые

Флизелиновые

Как видим, в таблице присутствуют дублирующиеся строки. Если же мы добавим в предложение Select distinct:

SELECT distinct Oboi.type

FROM Oboi order by type

то получим результат без повторов:

type

Бумажные

Бумажные двухслойные

Виниловые

Тканевые

Флизелиновые

Таким образом, если грамотно вносились данные в таблицы, то сразу по звонку или запросу покупателей мы сможем ответить, что жидких обоев, стеклообоев и акриловых обоев в наличии в магазине нет. Учитывая, что ассортимент в магазинах обычно не ограничивается одной сотней обоев, просмотреть перечень из неуникальных типов было бы довольно трудозатратно.

Применение distinct внутри агрегатных функций

Аргумент SQL distinct можно использовать с любой агрегатной функцией. Но для Min и Max его применение не даст никакого эффекта, а при вычислении суммы или среднего значения редко можно представить ситуацию, когда не нужно было бы учитывать повторы.

Допустим, мы хотим узнать, насколько заполнен наш склад, и для этого отправляем запрос, вычисляющий общее количество рулонов на складе:

SELECT sum(Ostatki.count)

FROM Ostatki

Запрос выдаст ответ 143. Если же мы изменим на:

SELECT sum(distinct Ostatki.count)

FROM Ostatki

то получим всего 119, ведь обои под артикулами 3 и 7 находятся на складе в одинаковом количестве. Однако очевидно, что этот ответ неверен.

Чаще всего в SQL distinct применяется с функцией Count. Так, без труда мы можем узнать, сколько уникальных видов обоев у нас вообще есть:

SELECT count(distinct Oboi.type)

FROM Oboi

И получить результат 5 – бумажные обычные и двухслойные, виниловые, тканевые и флизелиновые. Наверняка все видели рекламу типа: «Только у нас более 20 видов различных обоев!», под которой подразумевается, что в данном магазине не пара десятков рулонов всего, а обои самых разнообразных современных типов.

Интересно, что в одном запросе можно указывать несколько функций Count как с атрибутом distinct, так и без него. То есть это единственная ситуация, когда distinct в Select'е может присутствовать несколько раз.

Когда следует отказаться от применения аргумента

От применения аргумента SQL distinct следует отказаться в одном из двух случаев:

  1. Вы выполняете выборку из таблиц и уверены в уникальности значений в каждой. В таком случае применение аргумента нецелесообразно, ведь это дополнительная нагрузка на сервер или клиента (в зависимости от вида СУБД).
  2. Вы боитесь потерять нужные данные. Поясним.

Допустим, начальник просит вас вывести список обоев, которые у вас есть, с указанием всего двух столбцов – тип и цвет. По привычке вы указываете аргумент distinct:

SELECT distinct Oboi.type, Oboi.color

FROM Oboi

ORDER BY Oboi.type

И – теряете часть данных:

type

color

Бумажные

Мультиколор

Бумажные двухслойные

Беж

Виниловые

Коричневые

Виниловые

Оранж

Тканевые

Розовые

Флизелиновые

Беж

Флизелиновые

Белые

Может создаться впечатление, что бумажных обоев (обычных и двухслойных) у нас всего по одному виду, хотя на самом деле даже в нашей маленькой таблице их по два артикула (результат без distinct):

type

color

Бумажные

Мультиколор

Бумажные

Мультиколор

Бумажные двухслойные

Беж

Бумажные двухслойные

Беж

Виниловые

Коричневые

Виниловые

Оранж

Тканевые

Розовые

Флизелиновые

Белые

Флизелиновые

Беж

Поэтому, как и при написании любого запроса, с аргументом distinct надо быть аккуратным и грамотно решать вопрос с ее применением в зависимости от поставленной задачи.

Альтернатива distinct

Противоположность аргументу distinct – аргумент All. При его применении повторяющиеся строки сохраняются. Но поскольку по умолчанию СУБД так и считает, что нужно выводить все значения, то аргумент All – это скорее уточнитель, чем реальный функциональный аргумент.

Надеемся, что вам теперь понятно, когда применяется distinct (SQL). Описание дало вам полную информацию о целесообразности применения этого аргумента при решении разных задач. Ведь, как оказалось, даже такой простой аргумент в своем применении скрывает вполне ощутимую вероятность потерять некоторые данные и вывести неточную информацию.

Комментарии