Как найти дубликаты в SQL: GROUP BY, HAVING и проверка строк

Дубликаты в SQL чаще всего ищут через GROUP BY и HAVING COUNT(*) > 1. Но перед запросом нужно решить, что именно считать дублем. Для одного отчета дубль — это одинаковый email. Для другого — одинаковая пара «телефон и дата». Для третьего — полностью совпадающая строка во всех значимых столбцах

Если сразу искать «одинаковые строки» без определения правила, результат будет случайным. В базе почти всегда есть технический id, дата создания или служебное поле, из-за которых строки формально разные, хотя для бизнеса они выглядят как дубли

Найти дубли по одному полю

Пример: найти повторяющиеся email в таблице клиентов

SELECT
    email,
    COUNT(*) AS duplicate_count
FROM customers
GROUP BY email
HAVING COUNT(*) > 1;

Результат:

Такой запрос показывает значения, которые повторяются, но не показывает все строки целиком. Для первичной проверки этого достаточно

Показать строки-дубли полностью

Чтобы вывести сами строки, можно использовать подзапрос:

SELECT *
FROM customers
WHERE email IN (
    SELECT email
    FROM customers
    GROUP BY email
    HAVING COUNT(*) > 1
)
ORDER BY email, id;

Теперь вы увидите все записи с повторяющимися email и сможете понять, какие из них настоящие дубли, а какие просто разные клиенты с общим адресом

Найти дубли по нескольким столбцам

Часто одного поля мало. Например, заказ может считаться дублем, если совпадают клиент, дата и сумма:

SELECT
    customer_id,
    order_date,
    total_sum,
    COUNT(*) AS duplicate_count
FROM orders
GROUP BY customer_id, order_date, total_sum
HAVING COUNT(*) > 1;

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

Найти дубли через оконную функцию

Если нужно пометить повторные строки и оставить первую, удобно использовать ROW_NUMBER

WITH marked AS (
    SELECT
        id,
        email,
        created_at,
        ROW_NUMBER() OVER (
            PARTITION BY email
            ORDER BY created_at
        ) AS rn
    FROM customers
)
SELECT *
FROM marked
WHERE rn > 1;

Такой запрос показывает записи, которые считаются повторными внутри группы email. Первой остается самая ранняя запись по created_at

Как безопасно подходить к удалению дублей

Не удаляйте дубли сразу. Сначала:

  1. Найдите повторяющиеся значения
  2. Выведите полные строки
  3. Сохраните результат проверки
  4. Сделайте бэкап
  5. Уточните правило, какая строка остается
  6. Только потом пишите DELETE

Для удаления часто используют CTE с ROW_NUMBER, но это уже отдельная операция. В учебном материале лучше сначала научиться видеть дубли, потому что ошибочный DELETE исправлять намного сложнее

Мини-практика

Создайте тестовую таблицу:

CREATE TABLE customers (
    id int IDENTITY(1,1) PRIMARY KEY,
    name nvarchar(100) NOT NULL,
    email nvarchar(100) NOT NULL,
    created_at date NOT NULL
);

INSERT INTO customers (name, email, created_at)
VALUES
    (N'Анна', 'anna@example.com', '2026-01-10'),
    (N'Анна копия', 'anna@example.com', '2026-01-12'),
    (N'Илья', 'ilya@example.com', '2026-01-11');

Найдите повторяющиеся email:

SELECT email, COUNT(*) AS duplicate_count
FROM customers
GROUP BY email
HAVING COUNT(*) > 1;

Потом выведите полные строки по этому email и решите, какую запись вы бы оставили

Частые ошибки

  • Считают дублем всю строку вместе с id, поэтому ничего не находят
  • Ищут только по одному полю, хотя для задачи нужна комбинация столбцов
  • Удаляют дубли без бэкапа
  • Не проверяют NULL, пробелы и разный регистр букв
  • Не решают заранее, какая запись должна остаться
  • Путают поиск дублей с проверкой уникального индекса

Что почитать дальше по SQL

Если нужен общий маршрут по теме, откройте рубрику SQL. Для соседних задач пригодятся эти разборы:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x