2010-05-19 4 views
37

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

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

ответ

77

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

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

Edit: Обратите внимание, что эта команда may not work for InnoDB tables для некоторых версий MySQL. См. this post для обходного пути. (Спасибо «анонимному пользователю» за эту информацию.)

+0

Это отличный способ! – nc3b

+0

Это очень умно. – 2010-05-20 14:24:34

+9

Не работал для меня. (ошибка выполнения дублирования запроса) – Noam

9

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

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

More specifically:
Чем быстрее способ для вставки отдельных строк во временную таблицу. Используя 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; 
0

Это показывает, как это сделать в 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 
0
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 
) 
0

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

Однако у него есть один вопрос:

ERROR 1093 (HY000): Вы не можете указать целевую таблицу 'студент' для обновления в предложении FROM

Это, однако, может быть решена используя (SELECT * FROM студента) вместо студента:

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 к Нитин для придумывая оригинальное решение.

0

С MySql ALTER IGNORE TABLEhas been deprecated, вы должны фактически удалить дублируемую дату перед добавлением индекса.

Сначала напишите запрос, который находит все дубликаты. Здесь я предполагаю, что 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) 
; 
0

Ниже запроса может быть использована для удаления всех дубликатов, за исключением одной строки с наименьшим «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 
0

Удаление дубликатов в таблицах MySQL является общей проблемой, которая обычно встречается с определенными потребностями. В случае, если кому-то интересно, здесь (Remove duplicate rows in 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;