Виммельбух, 1, перетяжка
Виммельбух, 1, перетяжка
Виммельбух, 1, перетяжка

Простой  и эффективный метод удаления дубликатов из таблицы

Аватарка пользователя Slava Rozhnev
Отредактировано

Как быстро и просто удалить дубликаты данных в SQL-базе, чтобы избежать ошибок в программном коде, который использует эти данные.

12К открытий17К показов

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

В этой короткой статье я хочу поделиться простым способом удаления дубликатов из таблицы. Запрос работает в базах данных MySQL, MariaDB и PostgreSQL. Если вам интересен такой запрос для других СУБД, напишите мне в комментариях.

Все вышеизложенные а также любые другие запросы можно воспроизвести на SQLize.online – онлайн редакторе SQL.

Давайте начнем. Предположим, у нас есть простая таблица с двумя столбцами: id – это первичный ключ и v простое целочисленное значение

			create table tbl (
    id int primary key,
    val int
);

insert into tbl (id, val) values 
(1, 1), (2, 1), (3, 2), (4, 2), (5, 1), (6, 1),
(7, 2), (8, 3), (9, 2), (10, 4), (11, 3);
		

Приведенный выше код создает таблицу и вставляет несколько значений. Выведем на экран все строки из нашей тестовой таблицы. Как видите, id имеет уникальные значения, но поле val имеет содержит дубликаты:

			SELECT * FROM tbl;
+====+===+
| id | v |
+====+===+
| 1  | 1 |
| 2  | 1 |
| 3  | 2 |
| 4  | 2 |
| 5  | 1 |
| 6  | 1 |
| 7  | 2 |
| 8  | 3 |
| 9  | 2 |
| 10 | 4 |
| 11 | 3 |
+----+---+
		

Наша задача состоит в том, чтобы удалить строки с поввторяющимися значениями в столбце val и сохранить уникальные значения с минимальным значением идентификатора id.

Для начала попробуем найти дубликаты. Мы можем использовать простое LEFT JOIN таблицы самой с собой по полю val с дополнительным условием для предотвращения объединения идентичных строк (для наглядности дадим алиасы для таблицы и копии):

			select * 
from tbl source_tbl
left join tbl copy_tbl 
    on source_tbl.val = copy_tbl.val and 
       source_tbl.id > copy_tbl.id;
		

В результате запроса получим следующий результат:

			+====+===+========+========+
| id | val | id   | val    |
+====+===+========+========+
| 1  | 1 | (null) | (null) |
| 2  | 1 | 1      | 1      |
| 3  | 2 | (null) | (null) |
| 4  | 2 | 3      | 2      |
| 5  | 1 | 1      | 1      |
| 5  | 1 | 2      | 1      |
| 6  | 1 | 1      | 1      |
| 6  | 1 | 2      | 1      |
| 6  | 1 | 5      | 1      |
| 7  | 2 | 3      | 2      |
| 7  | 2 | 4      | 2      |
| 8  | 3 | (null) | (null) |
| 9  | 2 | 3      | 2      |
| 9  | 2 | 4      | 2      |
| 9  | 2 | 7      | 2      |
| 10 | 4 | (null) | (null) |
| 11 | 3 | 8      | 3      |
+----+---+--------+--------+
		

Видно, что уникальные строки с минимальным id имеют (null) в столбцах из copy_tbl. Это происходит потому что для минимального значения id в исходной таблице нет строк соответсвующих условию в таблице копии. Итак, нам нужно оставить строки в которых нет соответствия (уникальные) и удалить. Это можно осуществить следующим запросом:

			delete tbl.*
from tbl
left join t copy_tbl 
    on tbl.val = copy_tbl.val and tbl.id > copy_tbl.id
where copy_tbl.id is not null;
		

P.S. Уже после написания этой статьи мой коллега @Akina предложил более короткую версию:  

			delete tbl.*
from tbl
join t copy_tbl 
    on tbl.val = copy_tbl.val and tbl.id > copy_tbl.id;
		

Если Вам понравилась статья, Вы можете поддержать автора.

Следите за новыми постами
Следите за новыми постами по любимым темам
12К открытий17К показов