SQLLab
Все статьи

DISTINCT в SQL: убираем дубликаты и считаем уникальные значения

Как работает DISTINCT в SQL: примеры с одним и несколькими столбцами, COUNT DISTINCT, отличие от GROUP BY и когда лучше не использовать DISTINCT.

15 марта 2026 г.·4 мин чтения·

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

Базовый синтаксис

SELECT DISTINCT column1
FROM table_name;

DISTINCT применяется ко всему набору столбцов в SELECT, а не к одному из них.

Пример: список категорий

Таблица products:

idnamecategoryprice
1НоутбукЭлектроника85000
2МышьЭлектроника1500
3СтолМебель12000
4КреслоМебель25000
5МониторЭлектроника32000

Получить уникальные категории:

SELECT DISTINCT category FROM products;

Результат:

category
Электроника
Мебель

DISTINCT с несколькими столбцами

DISTINCT смотрит на комбинацию всех выбранных столбцов:

SELECT DISTINCT category, price
FROM products;

Вернёт уникальные пары (category, price). Если два товара одной категории по одной цене — одна из строк будет убрана.


COUNT(DISTINCT ...) — число уникальных значений

Самое частое применение DISTINCT — подсчёт уникальных значений:

-- Сколько разных категорий?
SELECT COUNT(DISTINCT category) AS unique_categories
FROM products;
-- Результат: 2
-- Сколько уникальных покупателей сделали заказ?
SELECT COUNT(DISTINCT user_id) AS unique_buyers
FROM orders;

Это работает и внутри GROUP BY:

-- Число уникальных покупателей по городу
SELECT city, COUNT(DISTINCT user_id) AS buyers
FROM orders
GROUP BY city;

DISTINCT vs GROUP BY

Часто DISTINCT и GROUP BY дают одинаковый результат:

-- Эквивалентные запросы:
SELECT DISTINCT category FROM products;

SELECT category FROM products GROUP BY category;

Когда предпочесть GROUP BY:

  • Когда нужны агрегатные функции (COUNT, SUM, AVG)
  • Когда нужен HAVING для фильтрации групп
  • Обычно GROUP BY лучше оптимизируется планировщиком

Когда DISTINCT уместен:

  • Когда просто нужны уникальные строки без агрегации
  • Код короче и намерение очевиднее

NULL и DISTINCT

DISTINCT считает все NULL одинаковыми и оставляет только один NULL:

SELECT DISTINCT manager_id FROM employees;
-- Если несколько сотрудников без менеджера (NULL) — будет один NULL

Это важно: в обычном SQL NULL = NULL возвращает NULL (не TRUE), но DISTINCT группирует NULL вместе.


Производительность DISTINCT

DISTINCT требует сортировки или хеширования всего результата для поиска дубликатов — это дорого на больших таблицах.

-- Медленно на миллионе строк без индекса
SELECT DISTINCT user_id FROM events;

Что делать:

  1. Убедитесь, что на столбец есть индекс
  2. Если нужно только проверить существование — используйте EXISTS
  3. Если структура данных правильная — дубликатов не должно быть вовсе
-- Вместо COUNT(DISTINCT) на большой таблице
-- Иногда быстрее:
SELECT COUNT(*) FROM (
    SELECT DISTINCT user_id FROM events
) sub;

DISTINCT ON — только в PostgreSQL

PostgreSQL поддерживает DISTINCT ON — выбрать уникальные строки по одному полю, сохраняя остальные:

-- Последний заказ каждого пользователя
SELECT DISTINCT ON (user_id)
    user_id,
    order_id,
    created_at
FROM orders
ORDER BY user_id, created_at DESC;

DISTINCT ON (user_id) оставляет одну строку на каждый user_id. Какую именно — определяет ORDER BY. В данном случае — самую свежую.

Это мощная альтернатива ROW_NUMBER() + WHERE rn = 1:

-- Эквивалент через оконную функцию:
SELECT user_id, order_id, created_at
FROM (
    SELECT *,
           ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn
    FROM orders
) t
WHERE rn = 1;

DISTINCT ON обычно немного быстрее и проще читается.


Антипаттерн: DISTINCT как заплатка

Нередко DISTINCT добавляют, чтобы «убрать дубликаты», не разобравшись почему они появились:

-- Плохо: зачем дубликаты вообще появились?
SELECT DISTINCT u.id, u.name
FROM users u
JOIN orders o ON u.id = o.user_id;
-- Каждый заказ создаёт отдельную строку — отсюда дубликаты

Правильное решение — либо использовать другой вид JOIN, либо переосмыслить запрос:

-- Хорошо: пользователи, у которых есть хоть один заказ
SELECT u.id, u.name
FROM users u
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);

Если DISTINCT нужен «чтобы убрать странные дубликаты» — это сигнал о проблеме в логике JOIN.


Итог

СценарийИнструмент
Уникальные значения столбцаSELECT DISTINCT col
Число уникальных значенийCOUNT(DISTINCT col)
Уникальные строки + агрегацияGROUP BY
Первая/последняя строка в группеDISTINCT ON (PostgreSQL)
Проверить существованиеEXISTS

DISTINCT — простой и нужный инструмент. Главное — не использовать его как заплатку для скрытия проблем в запросе.

Похожие статьи

Попробуй на практике

Тренажёр с реальными задачами — бесплатно и без регистрации

Открыть тренажёр →