Как удалить повторяющиеся записи из mysql db?

У меня есть таблица с некоторыми идентификаторами + заголовки. Я хочу сделать столбец заголовка уникальным, но он имеет более 600 тыс. Записей, некоторые из которых являются дубликатами (иногда несколько десятков раз).

Как удалить все дубликаты, кроме одного, поэтому я могу добавить ключ UNIQUE в столбец заголовка после?

Ответ 1

Эта команда добавляет уникальный ключ и удаляет все строки, которые генерируют ошибки (из-за уникального ключа). Это удаляет дубликаты.

ALTER IGNORE TABLE table ADD UNIQUE KEY idx1(title); 

Изменить: обратите внимание, что эта команда может не работать для таблиц InnoDB для некоторых версий MySQL. См. этот пост для обходного пути. (Спасибо "анонимному пользователю" за эту информацию.)

Ответ 2

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

CREATE TABLE tmp_table AS SELECT DISTINCT [....] FROM main_table

Подробнее:
Более быстрый способ - вставить отдельные строки во временную таблицу. Используя delete, мне потребовалось несколько часов, чтобы удалить дубликаты из таблицы из 8 миллионов строк. Используя вставку и отчетливую, потребовалось всего 13 минут.

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
DROP TABLE tableName;  
INSERT tableName SELECT * FROM tempTableName;  
DROP TABLE tempTableName;  

Ответ 3

Это показывает, как это сделать в SQL2000. Я не совсем знаком с синтаксисом MySQL, но я уверен, что что-то сравнимое

create table #titles (iid int identity (1, 1), title varchar(200))

-- Repeat this step many times to create duplicates
insert into #titles(title) values ('bob')
insert into #titles(title) values ('bob1')
insert into #titles(title) values ('bob2')
insert into #titles(title) values ('bob3')
insert into #titles(title) values ('bob4')


DELETE T  FROM 
#titles T left join 
(
  select title, min(iid) as minid from #titles group by title
) D on T.title = D.title and T.iid = D.minid
WHERE D.minid is null

Select * FROM #titles

Ответ 4

delete from student where id in (
SELECT distinct(s1.`student_id`) from student as s1 inner join student as s2
where s1.`sex` = s2.`sex` and
s1.`student_id` > s2.`student_id` and
s1.`sex` = 'M'
    ORDER BY `s1`.`student_id` ASC
)

Ответ 5

Решение, размещенное Nitin, кажется самым элегантным/логичным.

Однако у него есть одна проблема:

ОШИБКА 1093 (HY000): вы не можете указать целевую таблицу 'student' для обновление в предложении FROM

Однако это может быть разрешено с помощью (SELECT * FROM student) вместо ученика:

DELETE FROM student WHERE id IN (
SELECT distinct(s1.`student_id`) FROM (SELECT * FROM student) AS s1 INNER JOIN (SELECT * FROM student) AS s2
WHERE s1.`sex` = s2.`sex` AND
s1.`student_id` > s2.`student_id` AND
s1.`sex` = 'M'
ORDER BY `s1`.`student_id` ASC
)

Дайте вашему +1 Nitin для решения оригинального решения.

Ответ 6

Поскольку MySql ALTER IGNORE TABLE устарел, вам нужно фактически удалить дублируемую дату перед добавлением индекса.

Сначала напишите запрос, который найдет все дубликаты. Здесь я предполагаю, что email - это поле, содержащее дубликаты.

SELECT
    s1.email
    s1.id, 
    s1.created
    s2.id,
    s2.created 
FROM 
    student AS s1 
INNER JOIN 
    student AS s2 
WHERE 
    /* Emails are the same */
    s1.email = s2.email AND
    /* DON'T select both accounts,
       only select the one created later.
       The serial id could also be used here */
    s2.created > s1.created 
;

Далее выберите только уникальные идентификаторы дубликатов:

SELECT 
    DISTINCT s2.id
FROM 
    student AS s1 
INNER JOIN 
    student AS s2 
WHERE 
    s1.email = s2.email AND
    s2.created > s1.created 
;

Как только вы убедитесь, что только содержит дубликаты идентификаторов, которые вы хотите удалить, запустите удаление. Вы должны добавить (SELECT * FROM tblname), чтобы MySql не жаловался.

DELETE FROM
    student 
WHERE
    id
IN (
    SELECT 
        DISTINCT s2.id
    FROM 
        (SELECT * FROM student) AS s1 
    INNER JOIN 
        (SELECT * FROM student) AS s2 
    WHERE 
        s1.email = s2.email AND
        s2.created > s1.created 
);

Затем создайте уникальный индекс:

ALTER TABLE
    student
ADD UNIQUE INDEX
    idx_student_unique_email(email)
;

Ответ 7

Ниже запрос может быть использован для удаления всего дубликата, за исключением одной строки с наименьшим значением поля "id"

DELETE t1 FROM table_name t1, table_name t2 WHERE t1.id > t2.id AND t1.name = t2.name

Аналогичным образом мы можем сохранить строку с наивысшим значением в 'id' следующим образом

 DELETE t1 FROM table_name t1, table_name t2 WHERE t1.id < t2.id AND t1.name = t2.name

Ответ 8

Удаление дубликатов в таблицах MySQL является общей проблемой, обычно возникающей с конкретными потребностями. В случае, если кому-то интересно, здесь (Удалить повторяющиеся строки в MySQL). Я объясню, как использовать временную таблицу для удаления дубликатов MySQL надежным и быстрым способом (с примерами для различные варианты использования).

В этом случае что-то вроде этого должно работать:

-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;

-- add a unique constraint    
ALTER TABLE tmp_table1 ADD UNIQUE(id, title);

-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;

-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;