Как использование круглых скобок при использовании ключевого слова DISTINCT в SQL может вызвать путаницу

Одно из самых распространенных неверных толкований, которое допускают многие пользователи SQL, даже самые опытные, связано с тем, как DISTINCT применяется к указанным столбцам. Довольно часто можно увидеть запросы SQL, пытающиеся применить предложение SELECT DISTINCT к подмножеству столбцов, которые должны быть возвращены запросом.

И заблуждение заключается в представлении, что DISTINCT — это функция, которая по существу принимает имя столбца, к которому она будет применяться, в то время как столбцы, указанные вне «вызова функции», не будут учитываться при вычислении результатов.

Но на самом деле, когда вы пытаетесь использовать круглые скобки, чтобы попытаться сделать DISTINCT эффективным только для столбцов, заключенных в круглые скобки, это не сработает так, как вы ожидаете.

Теперь давайте создадим пример таблицы, на которую мы будем ссылаться в этой статье, чтобы продемонстрировать несколько концепций и помочь нам прояснить, как именно ключевое слово DISTINCT работает в SQL.

А теперь добавим несколько записей во вновь созданную таблицу address.

Теперь давайте запросим результаты, чтобы увидеть окончательный пример таблицы:

Заблуждение о DISTINCT в SQL

Теперь предположим, что мы хотим получить отдельные строки из нашей таблицы rental, используя два разных поля, а именно customer_id и store_id. Другими словами, мы хотели бы ответить на следующий вопрос:

Каковы уникальные комбинации customer_id и store_id в нашей таблице аренды?

Чтобы ответить на приведенный выше запрос, мы можем просто запросить нашу таблицу и получить значения DISTINCT для столбцов customer_id и store_id:

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

И именно в этом заключается неправильное представление о DISTINCT. У многих пользователей создается (ошибочное!) впечатление, что DISTINCT — это функция, в которой мы можем указать столбцы, которые мы хотим учитывать при ее применении к нашей целевой таблице.

Если вы попытаетесь заключить customer_id в круглые скобки при «вызове» (неподходящий глагол здесь, поскольку это не функция) DISTINCT, вы заметите, что это не имеет никакого эффекта:

Мы по-прежнему можем видеть «дублирующиеся» идентификаторы клиентов в результатах нашего запроса. Это связано с тем, что предложение SELECT DISTINCT всегда будет учитывать все указанные имена столбцов, независимо от того, были ли они заключены в круглые скобки.

На самом деле все приведенные ниже выражения действительно эквивалентны:

  • SELECT DISTINCT customer_id, store_id FROM rental;
  • SELECT DISTINCT (customer_id), store_id FROM rental;
  • SELECT DISTINCT (customer_id), (store_id) FROM rental;
  • SELECT DISTINCT (store_id), customer_id FROM rental;
  • SELECT DISTINCT ((customer_id)), store_id FROM rental;

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

PostgreSQL и DISTINCT ON

Если вы работаете с Postgres и хотели бы применить DISTINCT только к подмножеству столбцов, которые вы хотите получить в своих результатах, вы можете воспользоваться преимуществом DISTINCT ON.

SELECT DISTINCT удаляет повторяющиеся строки из результата.

SELECT DISTINCT ON удаляет строки, соответствующие всем указанным выражениям.

— Постгрес Документация

Это расширение построено на основе DISTINCT стандартного SQL и возвращает первую строку для каждого набора строк, соответствующих указанному выражению.

Однако обратите внимание, что при использовании DISTINCT ON имеет смысл также использовать предложение ORDER BY. Таким образом, вы сможете указать условия выбора желаемого результата из конфликтующих строк. Например, если две строки соответствуют вашему выражению (в приведенном выше примере у нас есть две записи, соответствующие клиенту с идентификатором 100).

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

Обратите внимание, что store_id, соответствующее customer_id=100, изменилось, поскольку строка аренды с наименьшей суммой отличается теперь, когда мы упорядочили наши результаты по сумме в порядке возрастания.

Но в целом, если вас не особо волнует порядок, то его можно опустить.

Последние мысли

Важно понимать, как ключевое слово DISTINCT работает с операторами SELECT в SQL, так как это является источником путаницы для многих пользователей, и я бы сказал, даже для опытных.

При написании запросов с предложениями SELECT DISTINCT многие пользователи склонны использовать DISTINCT так же, как и с правильными функциями SQL. Другими словами, они заключают один столбец в круглые скобки, в то же время они предоставляют больше имен столбцов после предложения — например, SELECT DISTINCT(user_id), first_name FROM ....

При чтении таких запросов (и, очевидно, людей, их пишущих) вы можете прийти к выводу, что SELECT DISTINCT применимо только к указанному столбцу (например, user_id), а не к остальным столбцам (например, first_name). И, как мы видели в сегодняшней статье, это заблуждение и довольно опасное предположение при написании запросов.

Наконец, мы обсудили особый случай в базе данных PostgreSQL, который позволяет пользователям явно указать, какой столбец следует учитывать при применении DISTINCT, используя специальное предложение DISTINCT ON.

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



Статьи по теме, которые вам также могут понравиться