TGViewer
Spring АйО Spring АйО @spring_aio · 11K subscribers
Post #244 5.21K
🗑 Удаление дублирующихся строк

Со временем в любом приложении могут появиться дублирующиеся записи. Иногда их удаление реализуют на уровне приложения, хотя это можно сделать с помощью одного SQL-запроса.

Удалить дубликаты вручную не так просто, как может показаться. Обычно для этого используется команда GROUP BY с функциями MIN(id) или MAX(id), чтобы оставить одну строку.

⚠️ Будьте крайне аккуратны при выполнении DML-запросов. Во избежании потери данных рекоммендуем сделать backup таблицы, которую планируете изменить.


DELETE FROM contacts
WHERE id NOT IN (
SELECT MIN(id)
FROM contacts
GROUP BY firstname, lastname, email
);


Однако такой метод не всегда подходит, если есть дополнительные требования:
* Нужно сохранить не все дубликаты, а лишь часть, например, последние пять.
* Иногда важно не просто удалить первые или последние строки — дополнительные поля могут задавать приоритет, например, мы не хотим удалять пользователя, подтвердившего email, ради того, который этого не сделал.

Чтобы учесть все требования, можно воспользоваться оконными функциями:
1. Строки разбиваются на группы по дублирующимся полям, создавая отдельные группы для каждого уникального набора значений.
2. Каждая группа сортируется по важным полям, например, по дате создания.
3. Для каждой строки в группе с помощью функции ROW_NUMBER назначается порядковый номер.
4. Можно удалить любые строки с номером, превышающим необходимый, например, если нужно оставить только пять последних записей.

Тогда, запрос позволяющий сохранить не все дубликаты, а лишь часть, например, последние пять, будет выглядеть следующим образом:


WITH duplicates AS (
SELECT id, ROW_NUMBER() OVER(
PARTITION BY firstname, lastname, email
ORDER BY age DESC
) AS rownum
FROM contacts
)
DELETE FROM contacts
USING duplicates
WHERE contacts.id = duplicates.id AND duplicates.rownum > 5;


А запрос, для удаления дубликатов с учетом факта подтверждения email следующим образом:


WITH duplicates AS (
SELECT
id,
ROW_NUMBER() OVER(
PARTITION BY email
ORDER BY email_confirmed DESC
) AS rownum
FROM contacts
)
DELETE FROM contacts
USING duplicates
WHERE contacts.id = duplicates.id AND duplicates.rownum > 1;


#DatabaseTip #SQL
  • 👍 37
  • ❤ 5
  • 🔥 4
  • 🤩 1
More from @spring_aio
  1. Oct 11, 2026🎬 Записи докладов с JPoint 2026 уже в открытом доступе JUG Ru Group выложили записи с про…
  2. Oct 9, 2026👩‍💻 Kotlin получил почти настоящие статики Начиная с Kotlin 2.5.0-Beta1 можно эксперимен…
  3. Oct 8, 2026🍃 Spring Boot ломает совместимость, G1 тормозит микросервисы, Java долго релизит фичи | S…
  4. Oct 6, 2026👩‍💻 Spring Config Import без магии У наших друзей из Axelix вышла статья о том, как Spri…
  5. Oct 5, 2026🥲 В Java 27 TLS научился переживать квантовую атаку При установке HTTPS-соединения клиент…
  6. Oct 3, 2026⚡️⚡️Строки кода стремятся подешеветь до цены токена. Что остается ценным? Про это — трек «…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →