SELECT DISTINCT: уникальные значения
SELECT DISTINCT: уникальные значения
В предыдущем уроке вы научились выбирать конкретные колонки и давать им псевдонимы. Теперь столкнёмся с типичной задачей: «дай мне список всех категорий товаров в магазине». Если просто написать SELECT category FROM products, вы получите категорию для каждой строки — с повторениями. DISTINCT решает эту задачу: он убирает дубликаты из результата.
Проблема дублирования
Представьте таблицу products с тысячами строк. У каждого товара есть поле category. Если в магазине 500 ноутбуков, 300 мышей и 200 мониторов, простой запрос вернёт 1000 строк:
SELECT category
FROM products;
Результат:
category
-----------
Электроника
Электроника
Периферия
Электроника
Периферия
... (995 строк ещё)
Это не то, что нужно. Нужен список уникальных категорий — три строки, а не тысяча.
Синтаксис SELECT DISTINCT
DISTINCT ставится сразу после ключевого слова SELECT:
SELECT DISTINCT category
FROM products;
Результат:
category
-----------
Электроника
Периферия
Мониторы
Три строки вместо тысячи. СУБД автоматически убрала повторяющиеся значения. Порядок строк в результате не гарантирован — если нужна сортировка, это отдельная клауза, которую мы разберём в модуле 3.
DISTINCT по нескольким колонкам
DISTINCT работает не с отдельной колонкой, а с полным набором выбранных колонок. Если указать две колонки, уникальными будут их комбинации:
SELECT DISTINCT department, position
FROM employees;
Таблица employees:
id | name | department | position
---+---------+---------------+----------
1 | Анна | Разработка | Junior
2 | Борис | Разработка | Senior
3 | Вера | Разработка | Junior
4 | Гриша | Менеджмент | Manager
5 | Дина | Разработка | Senior
Запрос вернёт уникальные пары (department, position):
department | position
------------+---------
Разработка | Junior
Разработка | Senior
Менеджмент | Manager
Обратите внимание: Анна и Вера обе «Разработка / Junior» — это одна строка в результате. Борис и Дина — «Разработка / Senior» — тоже одна строка. Всего три уникальных комбинации.
Проверь себя: сколько строк вернёт SELECT DISTINCT department FROM employees для таблицы выше?
DISTINCT с одной колонкой: практические сценарии
SELECT DISTINCT часто используют для разведки данных — чтобы понять, какие значения вообще встречаются в колонке:
SELECT DISTINCT status FROM orders; -- какие статусы заказов бывают?
SELECT DISTINCT country FROM customers; -- из каких стран клиенты?
SELECT DISTINCT rating FROM reviews; -- какие оценки есть в отзывах?
Это намного удобнее, чем просматривать тысячи строк вручную. DISTINCT — первый инструмент аналитика при изучении незнакомой базы данных.
Цена DISTINCT: производительность
DISTINCT не бесплатен. Чтобы убрать дубликаты, СУБД должна сравнить все строки между собой — это дополнительная работа. На больших таблицах без индексов SELECT DISTINCT может быть медленным.
Для ознакомительных запросов это не проблема. Но если вы используете DISTINCT в запросе, который выполняется тысячи раз в секунду, стоит подумать об оптимизации. Пока запомните: DISTINCT — мощный инструмент, но не «бесплатная» операция.
Типичные ошибки
1. DISTINCT не в том месте:
SELECT category DISTINCT FROM products; -- синтаксическая ошибка
DISTINCT стоит сразу после SELECT, не после списка колонок.
2. Ожидание сортировки:
SELECT DISTINCT category FROM products;
Порядок строк не гарантирован — Периферия может оказаться первой или последней. Если нужен алфавитный порядок, добавьте ORDER BY — об этом в следующем модуле.
3. SELECT DISTINCT * — работает, но редко полезен:
SELECT DISTINCT * FROM products;
Это уберёт только полностью идентичные строки (все колонки совпадают). В большинстве таблиц с id такое невозможно, и DISTINCT * ничего не убирает. Обычно при работе с DISTINCT * это сигнал, что в данных проблема — дублирующиеся строки, которых не должно быть.
Проверь себя: таблица employees содержит строки с (Разработка, Junior), (Разработка, Senior), (Менеджмент, Manager), (Разработка, Senior). Сколько строк вернёт SELECT DISTINCT department, position FROM employees?
NULL и DISTINCT
DISTINCT обрабатывает NULL особым образом: несколько NULL в одной колонке сворачиваются в один NULL. То есть DISTINCT считает все NULL одинаковыми — даже в тех случаях, когда в других контекстах SQL рассматривает NULL как «неизвестное» значение. Подробнее про NULL — в модуле 4, а пока просто знайте: DISTINCT и NULL дружат нормально.
Где DISTINCT не нужен
Иногда новички добавляют DISTINCT «на всякий случай» даже там, где дубликатов и так нет — например, при запросе к колонке с первичным ключом. Первичный ключ уникален по определению:
SELECT DISTINCT id FROM products; -- DISTINCT здесь ничего не делает
SELECT id FROM products; -- эквивалентно, но быстрее
Лишний DISTINCT — это ненужная нагрузка на СУБД. Используйте его осознанно, только когда реально нужны уникальные значения.
DISTINCT и псевдонимы
DISTINCT хорошо сочетается с псевдонимами из предыдущего урока. Можно давать колонкам читаемые имена и одновременно убирать дубликаты:
SELECT DISTINCT category AS "Категория",
country AS "Страна производителя"
FROM products;
Это вернёт уникальные пары «категория + страна». Псевдонимы работают так же, как и без DISTINCT.
Как DISTINCT влияет на количество строк
Полезно думать о DISTINCT как о «коллапсе» одинаковых строк. Возьмём таблицу из 10 строк с 3 разными значениями status:
id | status
---+----------
1 | pending
2 | shipped
3 | pending
4 | delivered
5 | pending
6 | shipped
7 | delivered
8 | pending
9 | shipped
10 | delivered
Без DISTINCT:
SELECT status FROM orders; -- 10 строк
С DISTINCT:
SELECT DISTINCT status FROM orders; -- 3 строки: pending, shipped, delivered
Это резкое сокращение результата. Именно поэтому DISTINCT — первый инструмент при «разведке» данных: вы быстро видите полный спектр значений в колонке.
DISTINCT ON в PostgreSQL
PostgreSQL предлагает расширение стандартного SQL — конструкцию DISTINCT ON (колонка). Она более гибкая: оставляет одну строку на каждое уникальное значение указанной колонки, выбирая первую попавшуюся (или первую по ORDER BY).
SELECT DISTINCT ON (department) department, name, salary
FROM employees
ORDER BY department, salary DESC;
Это вернёт по одному сотруднику из каждого отдела — с наибольшей зарплатой. DISTINCT ON — фича только PostgreSQL, её нет в стандартном SQL. Пока запомните её как «есть такая штука», детали не нужны.
Проверь понимание на примере
Дана таблица sales (продажи):
id | product | region | year
---+------------+-----------+------
1 | Ноутбук | Москва | 2023
2 | Мышь | СПб | 2023
3 | Ноутбук | Москва | 2024
4 | Монитор | Москва | 2023
5 | Мышь | Москва | 2024
6 | Ноутбук | СПб | 2023
Запрос:
SELECT DISTINCT product, region
FROM sales;
Сколько строк в результате? Уникальных пар (product, region): Ноутбук/Москва, Мышь/СПб, Ноутбук/СПб, Монитор/Москва, Мышь/Москва — итого 5 строк. Строка (Ноутбук, Москва) встречалась дважды (2023 и 2024), но в результате — один раз.
Краткий итог
SELECT DISTINCT колонка FROM таблицаубирает повторяющиеся строки из результатаDISTINCTставится сразу послеSELECT, перед списком колонок- При нескольких колонках
DISTINCTоставляет уникальные комбинации значений - Порядок строк в результате не гарантирован
DISTINCTтребует дополнительных вычислений — не злоупотребляйте им без нуждыNULLв контекстеDISTINCTсчитаются одинаковыми и сворачиваются в один- PostgreSQL поддерживает
DISTINCT ON (колонка)— расширение для выбора первой строки из группы
Что дальше
Теперь вы умеете получать уникальные значения. Следующий шаг — вычислять новые значения прямо в запросе: арифметику, строковые операции, константы. Это мощный инструмент, который называется «литералы и вычисляемые колонки» — разберём в следующем уроке.