
Оператор DISTINCT исключает повторяющиеся значения из результатов запроса, оставляя только уникальные строки. Он применяется в сочетании с SELECT и особенно полезен при работе с таблицами, где одни и те же данные могут встречаться многократно, например, при анализе заказов, списков пользователей или логов.
При выполнении запроса с DISTINCT сервер сортирует или хеширует данные, чтобы сравнить строки и отфильтровать дубликаты. Этот процесс может потребовать значительных ресурсов, особенно на больших объемах данных. Поэтому рекомендуется использовать оператор только там, где действительно необходимо убрать повторения, а не как универсальное решение для «очистки» выборки.
Оператор можно применять как к одному столбцу, так и к нескольким. В последнем случае уникальность определяется комбинацией значений всех перечисленных полей. Например, SELECT DISTINCT city, country вернёт уникальные пары «город–страна», а не просто список городов.
Чтобы повысить производительность, важно правильно индексировать столбцы, по которым выполняется DISTINCT. Если таблица не имеет подходящих индексов, сервер будет вынужден обрабатывать все строки последовательно, что замедлит выполнение запроса.
Синтаксис DISTINCT на примере простого SELECT-запроса

Оператор DISTINCT размещается сразу после ключевого слова SELECT и указывает СУБД вернуть только уникальные значения выбранных столбцов. Его можно применять как к одному столбцу, так и к комбинации нескольких.
Базовая форма запроса:
SELECT DISTINCT column_name FROM table_name;
Пример: пусть есть таблица employees со столбцом department, в котором могут повторяться значения. Чтобы получить список отделов без дубликатов:
SELECT DISTINCT department FROM employees;
Результат будет содержать каждое уникальное значение столбца department ровно один раз. Сортировка при этом не гарантируется, поэтому для фиксированного порядка можно добавить ORDER BY:
SELECT DISTINCT department FROM employees ORDER BY department;
Если указать несколько столбцов, уникальность будет определяться по комбинации всех выбранных полей:
SELECT DISTINCT department, position FROM employees;
Такой запрос исключит полные дубликаты строк, где совпадают и отдел, и должность.
Как DISTINCT устраняет дубликаты строк на уровне результата

Оператор DISTINCT применяется после формирования набора данных оператором SELECT. Его задача – удалить идентичные строки, оставив только уникальные комбинации значений выбранных столбцов.
Алгоритм работы обычно включает следующие этапы:
- Выполняется выборка всех строк, подходящих под условия запроса.
- Результат сортируется или хешируется по выбранным столбцам, чтобы можно было выявить повторяющиеся комбинации.
- Дубликаты отбрасываются, в итоговую выборку попадает только одна строка из каждой группы совпадающих значений.
Если DISTINCT применяется к нескольким столбцам, уникальность оценивается по совокупности всех этих столбцов. Например:
SELECT DISTINCT city, country FROM customers;
В данном случае строка считается повторяющейся, только если значения city и country совпадают одновременно.
При больших объёмах данных использование DISTINCT может быть ресурсоёмким. Чтобы минимизировать нагрузку:
- Ограничивайте число столбцов, к которым применяется DISTINCT.
- Используйте индексы на участвующих полях для ускорения сортировки или хеширования.
- Фильтруйте данные на этапе WHERE, уменьшая промежуточный набор строк.
Важно учитывать, что DISTINCT применяется уже после всех объединений и вычислений в SELECT, но до ORDER BY. Поэтому если требуется определённый порядок отображения уникальных строк, сортировку нужно задавать отдельно.
Использование DISTINCT для отдельных столбцов и их комбинаций

Оператор DISTINCT может применяться как к одному столбцу, так и к нескольким сразу. От того, сколько полей указано после DISTINCT, зависит логика формирования уникальных наборов данных.
1. Один столбец
- При выборе одного столбца DISTINCT убирает дубликаты только в этом поле, независимо от содержимого остальных.
- Пример: выбор уникальных городов из таблицы клиентов:
SELECT DISTINCT city
FROM customers;
- Результат будет содержать каждый город один раз, даже если в таблице десятки записей с одинаковым названием.
2. Несколько столбцов
- Если указать несколько полей, DISTINCT учитывает комбинации значений. Уникальность проверяется по набору сразу всех перечисленных столбцов.
- Пример: выбор уникальных пар «город – страна»:
SELECT DISTINCT city, country
FROM customers;
- Если один и тот же город встречается в нескольких странах, каждая комбинация будет отдельной строкой.
- При наличии одинаковых записей по обоим полям повторяющиеся пары будут исключены.
3. Практические рекомендации
- Чётко определяйте, по каким полям требуется уникальность. DISTINCT по всем колонкам таблицы может быть избыточным и замедлять запрос.
- Для больших таблиц полезно создавать индексы по тем полям, которые участвуют в DISTINCT, чтобы ускорить обработку.
- Если нужно исключить дубликаты только по одному полю, но при этом получить остальные столбцы, DISTINCT не подходит – используйте агрегирующие функции или подзапросы.
Отличия между DISTINCT и GROUP BY при работе с одинаковыми данными

Оператор DISTINCT удаляет дублирующиеся строки и возвращает уникальные комбинации значений без дополнительной обработки. Он подходит, когда требуется просто исключить повторы, не выполняя вычислений.
GROUP BY группирует строки по указанным полям и часто используется совместно с агрегатными функциями (COUNT, SUM, AVG). Даже без агрегатов он возвращает один результат на каждую группу, что может совпадать с поведением DISTINCT, но механизм работы отличается.
Если запрос содержит только одно поле, результаты DISTINCT и GROUP BY совпадут, однако GROUP BY потребует сортировки групп и может работать медленнее на больших объёмах данных без индексов. DISTINCT в таких случаях оптимизируется проще и использует уникальные индексы эффективнее.
При использовании нескольких полей DISTINCT анализирует полные строки, а GROUP BY создаёт логические группы по тем же наборам полей. Разница проявляется, когда добавляются агрегатные функции: GROUP BY может вычислять значения для каждой группы, в то время как DISTINCT не выполняет расчётов.
Практический совет: если нужно получить уникальные строки без вычислений – используйте DISTINCT. Если требуется анализ по группам или агрегирование – применяйте GROUP BY. Это упрощает запрос и снижает нагрузку на СУБД.
Применение DISTINCT в агрегатных функциях, например COUNT

Оператор DISTINCT в агрегатных функциях позволяет исключать дублирующиеся значения до выполнения вычислений. Это особенно важно при использовании COUNT, когда нужно посчитать количество уникальных элементов в столбце, а не общее число строк.
Пример: таблица orders содержит столбец customer_id, где один и тот же клиент может встречаться несколько раз. Чтобы узнать, сколько уникальных клиентов оформляли заказы, используется запрос:
SELECT COUNT(DISTINCT customer_id) AS unique_customers
FROM orders;
В отличие от COUNT(customer_id), который учитывает каждое вхождение, вариант с DISTINCT вернёт точное количество различных идентификаторов.
Комбинирование DISTINCT с другими агрегатными функциями также возможно. Например, в выражении SUM(DISTINCT amount) суммируются только уникальные значения суммы заказов, что полезно при анализе без повторяющихся транзакций.
Использование DISTINCT внутри агрегатов повышает точность аналитики, но может замедлить обработку на больших объёмах данных. Рекомендуется применять его только к тем полям, где дубли действительно искажают результат.
Особенности DISTINCT при работе с NULL и пустыми значениями
В SQL оператор DISTINCT рассматривает значения NULL как эквивалентные между собой при определении уникальности. Это означает, что несколько записей с NULL в одной колонке будут представлены как одно уникальное значение в результате запроса.
Пример поведения DISTINCT с NULL:
| id | |
|---|---|
| 1 | user1@example.com |
| 2 | NULL |
| 3 | user2@example.com |
| 4 | NULL |
Запрос:
SELECT DISTINCT email FROM users;
Результат:
| user1@example.com |
| user2@example.com |
| NULL |
Пустые строки (») DISTINCT обрабатывает как обычное значение, отличное от NULL. Несколько записей с пустой строкой будут считаться одинаковыми и сведены к одной.
Рекомендации при работе с NULL и пустыми значениями:
- При необходимости различать NULL и пустые строки используйте конструкцию
COALESCE(column, '')для приведения NULL к конкретному значению перед DISTINCT. - Для нескольких колонок DISTINCT учитывает комбинацию значений. Если хотя бы в одной колонке значение NULL, оно участвует в сравнении как одно уникальное значение.
- При агрегации или фильтрации NULL желательно явно проверять через
IS NULLилиIS NOT NULL, чтобы избежать непредсказуемых результатов.
Пример для нескольких колонок:
| id | first_name | last_name |
|---|---|---|
| 1 | Иван | NULL |
| 2 | Иван | Петров |
| 3 | Иван | NULL |
Запрос:
SELECT DISTINCT first_name, last_name FROM users;
Результат:
| first_name | last_name |
|---|---|
| Иван | NULL |
| Иван | Петров |
Таким образом, DISTINCT корректно группирует NULL и пустые строки, но различает их между собой. Это важно учитывать при очистке данных и построении отчетов.
DISTINCT в подзапросах и вложенных выборках

Использование DISTINCT в подзапросах позволяет ограничить внутренний набор уникальными значениями до объединений или фильтрации. Пример: SELECT id, name FROM users WHERE id IN (SELECT DISTINCT user_id FROM orders) гарантирует, что каждый пользователь рассматривается только один раз, даже если у него несколько заказов.
Во вложенных выборках DISTINCT снижает количество промежуточных строк при JOIN. Например, SELECT c.id, o.total FROM customers c JOIN (SELECT DISTINCT customer_id, total FROM orders) o ON c.id = o.customer_id исключает дублирование заказов при множественных совпадениях.
DISTINCT в подзапросах с агрегатами помогает получить точные группы. Например, SELECT region, (SELECT COUNT(DISTINCT product_id) FROM sales s WHERE s.region = r.region) AS unique_products FROM regions r возвращает количество уникальных продуктов по каждому региону без дублирования.
Для больших таблиц важно учитывать производительность. DISTINCT требует сортировки или хеширования, поэтому стоит проверять индексы на столбцах, участвующих в подзапросе, и при необходимости использовать оконные функции вместо многократных DISTINCT.
В коррелированных подзапросах DISTINCT предотвращает повторное включение строк. Пример: SELECT name FROM customers c WHERE EXISTS (SELECT DISTINCT customer_id FROM orders o WHERE o.customer_id = c.id AND o.total > 1000) гарантирует, что клиент учитывается единожды при проверке условий.
Комбинация DISTINCT с LIMIT или TOP в подзапросах изменяет порядок обработки: сначала удаляются дубликаты, затем применяется ограничение. Это критично при выборках топ-N уникальных записей.
Типичные ошибки при использовании DISTINCT и способы их избежать

Ошибка 1: Применение DISTINCT ко всем колонкам без необходимости. Часто разработчики используют DISTINCT *, чтобы убрать дубликаты, не анализируя, какие именно столбцы вызывают повторения. Это приводит к снижению производительности на больших таблицах. Решение: явно указывайте только те столбцы, по которым нужно удалить дубликаты, например: SELECT DISTINCT column1, column2 FROM table.
Ошибка 2: Ожидание удаления дубликатов после агрегатных функций. DISTINCT применяется к результату выборки до агрегирования. Если нужно удалить дубликаты после суммирования или подсчета, нужно использовать GROUP BY. Решение: заменять DISTINCT на GROUP BY column при работе с SUM, COUNT, AVG и другими агрегатами.
Ошибка 3: Игнорирование NULL значений. В SQL DISTINCT рассматривает несколько NULL как одинаковые значения, что может влиять на точность подсчетов. Решение: при необходимости различать NULL, использовать COALESCE(column, ‘значение по умолчанию’) перед применением DISTINCT.
Ошибка 4: Использование DISTINCT в подзапросах без индексов. На больших таблицах это может привести к значительным задержкам. Решение: создавать индексы на колонках, по которым выполняется DISTINCT, или предварительно фильтровать данные через WHERE.
Ошибка 5: Попытка удалить дубликаты, вызванные соединениями (JOIN). DISTINCT не решает проблему повторов, образующихся из-за множественных совпадений в связанных таблицах. Решение: проверять логику JOIN, использовать подзапросы с DISTINCT или применять агрегатные функции с GROUP BY для очистки результатов.
Вопрос-ответ:
Что делает оператор DISTINCT в SQL?
Оператор DISTINCT используется для удаления повторяющихся строк из результатов запроса. Если в таблице есть несколько записей с одинаковыми значениями в указанных столбцах, DISTINCT оставит только уникальные комбинации этих значений. Это помогает получить список без дубликатов, что часто нужно для анализа данных или формирования отчетов.
Можно ли использовать DISTINCT сразу для нескольких столбцов?
Да, DISTINCT может применяться к нескольким столбцам одновременно. В этом случае уникальность определяется комбинацией значений всех выбранных столбцов. Например, запрос SELECT DISTINCT имя, город FROM сотрудники вернет уникальные пары имя–город, а не только уникальные имена или уникальные города.
Как оператор DISTINCT влияет на производительность запроса?
Применение DISTINCT может замедлять выполнение запроса, особенно на больших таблицах, потому что базе данных приходится проверять и фильтровать повторяющиеся строки. В некоторых случаях использование группировки GROUP BY может быть быстрее, а также имеет смысл ограничивать выборку по условиям WHERE перед применением DISTINCT.
Чем отличается DISTINCT от GROUP BY?
Оба оператора могут возвращать уникальные значения, но работают по-разному. DISTINCT просто убирает повторяющиеся строки в выбранных столбцах, а GROUP BY группирует данные для агрегатных функций, таких как COUNT или SUM. Если нужно только убрать дубликаты без вычислений, лучше использовать DISTINCT. Для подсчета сумм или количества элементов удобнее GROUP BY.
Можно ли использовать DISTINCT вместе с агрегатными функциями?
Да, DISTINCT можно применять внутри агрегатных функций. Например, COUNT(DISTINCT колонка) посчитает количество уникальных значений в указанном столбце. Это полезно, если нужно узнать, сколько разных клиентов совершали покупки или сколько уникальных категорий товаров присутствует в таблице.
