Как найти дубликаты в SQL
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Зачем это знать
Дубликаты ломают аналитику: double counting revenue, завышенные активные пользователи, неверные конверсии. На собесах вопрос «как найти дубликаты в таблице» — базовый screen на SQL.
Чистка дубликатов — одна из частых задач в ETL и ad-hoc анализе. Знать 3-4 способа (и их trade-offs) — обязательно для middle.
Способ 1: GROUP BY + HAVING
Самый читаемый способ — найти строки с COUNT > 1.
SELECT email, COUNT(*) AS cnt
FROM users
GROUP BY email
HAVING COUNT(*) > 1;Быстро, понятно. Но покажет только duplicate keys — не full rows.
Способ 2: ROW_NUMBER
Нужны все поля дубликатов? Используйте оконную функцию.
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at) AS rn
FROM users
)
SELECT * FROM ranked WHERE rn > 1;Вернёт все дубликаты кроме первого. Удобно для удаления.
Способ 3: COUNT OVER
Все строки где дубликаты встречаются:
SELECT * FROM (
SELECT *, COUNT(*) OVER (PARTITION BY email) AS cnt
FROM users
) t WHERE cnt > 1;Включая первое вхождение. Для анализа всех duplicate rows.
Удаление дубликатов
Через CTE + DELETE
WITH ranked AS (
SELECT ctid,
ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at) AS rn
FROM users
)
DELETE FROM users
WHERE ctid IN (SELECT ctid FROM ranked WHERE rn > 1);Postgres-specific (ctid). В MySQL — через primary key.
Через DISTINCT
Если нужно просто получить unique values:
SELECT DISTINCT email, name FROM users;Не удаляет из таблицы, возвращает unique set.
Дубликаты по composite key
Дубликат по двум полям:
SELECT user_id, product_id, COUNT(*) AS cnt
FROM orders
GROUP BY user_id, product_id
HAVING COUNT(*) > 1;Часто встречается: одинаковый user + product = duplicate order.
Fuzzy-дубликаты
Одинаковые emails с разным case:
SELECT LOWER(email), COUNT(*) FROM users
GROUP BY LOWER(email) HAVING COUNT(*) > 1;Или с trailing spaces:
SELECT TRIM(email), COUNT(*) FROM users
GROUP BY TRIM(email) HAVING COUNT(*) > 1;На собесе
Типичный вопрос: «В таблице users поле email. Найдите всех, у кого email встречается больше одного раза».
Идеальный ответ: покажите GROUP BY, потом упомяните ROW_NUMBER для «если нужны все поля».
Связанные темы
FAQ
Какой способ самый быстрый?
GROUP BY — обычно быстрее ROW_NUMBER на больших данных.
DISTINCT подходит?
Для отдельного выбора unique — да. Для поиска дубликатов — нет.
Как удалить полностью (кроме одной копии)?
ROW_NUMBER + DELETE где rn > 1.
Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.