如何删除MySQL表上的重复项?

我需要删除mysql表上指定sid的重复行。

我怎样才能做到这一点与SQL查询?

DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1" 

这样的事情,但我不知道该怎么做。

这将删除重复的地方,而不是一个新的表

 ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID) 

注意:只有索引适合内存才能正常工作

假设你有一个表employee ,有以下几列:

 employee (first_name, last_name, start_date) 

为了删除具有重复的first_name列的行:

 delete from employee using employee, employee e1 where employee.id > e1.id and employee.first_name = e1.first_name 

在删除所有SID-s的重复项之后,不仅仅是单一的。

用临时表

 CREATE TABLE table_temp AS SELECT * FROM table GROUP BY title, SID; DROP TABLE table; RENAME TABLE table_temp TO table; 

由于temp_table是新创build的,它没有索引。 删除重复项之后,您需要重新创build它们。 您可以使用SHOW INDEXES IN table查看表中的索引

没有临时表:

 DELETE FROM `table` WHERE id IN ( SELECT all_duplicates.id FROM ( SELECT id FROM `table` WHERE (`title`, `SID`) IN ( SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1 ) ) AS all_duplicates LEFT JOIN ( SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1 ) AS grouped_duplicates ON all_duplicates.id = grouped_duplicates.id WHERE grouped_duplicates.id IS NULL ) 

在MySQL中删除重复的行,演练

创build表格并插入一些行:

 dev-db> create table penguins(foo int, bar varchar(15), baz datetime); Query OK, 0 rows affected (0.07 sec) dev-db> insert into penguins values(1, 'skipper', now()); dev-db> insert into penguins values(1, 'skipper', now()); dev-db> insert into penguins values(3, 'kowalski', now()); dev-db> insert into penguins values(3, 'kowalski', now()); dev-db> insert into penguins values(3, 'kowalski', now()); dev-db> insert into penguins values(4, 'rico', now()); Query OK, 6 rows affected (0.07 sec) dev-db> select * from penguins; +------+----------+---------------------+ | foo | bar | baz | +------+----------+---------------------+ | 1 | skipper | 2014-08-25 14:21:54 | | 1 | skipper | 2014-08-25 14:21:59 | | 3 | kowalski | 2014-08-25 14:22:09 | | 3 | kowalski | 2014-08-25 14:22:13 | | 3 | kowalski | 2014-08-25 14:22:15 | | 4 | rico | 2014-08-25 14:22:22 | +------+----------+---------------------+ 6 rows in set (0.00 sec) 

然后删除重复项:

 dev-db> delete a -> from penguins a -> left join( -> select max(baz) maxtimestamp, foo, bar -> from penguins -> group by foo, bar) b -> on a.baz = maxtimestamp and -> a.foo = b.foo and -> a.bar = b.bar -> where b.maxtimestamp IS NULL; Query OK, 3 rows affected (0.01 sec) 

结果:

 dev-db> select * from penguins; +------+----------+---------------------+ | foo | bar | baz | +------+----------+---------------------+ | 1 | skipper | 2014-08-25 14:21:59 | | 3 | kowalski | 2014-08-25 14:22:15 | | 4 | rico | 2014-08-25 14:22:22 | +------+----------+---------------------+ 3 rows in set (0.00 sec) 

那是什么删除语句呢

伪代码:按两列删除重复的行。 使用最大聚合来select每个组的一行。 左连接返回左表中的所有行,右表中的匹配行返回。 在这种情况下,左表具有表中的所有行,右侧仅包含那些为NULL的行(而不是每个组要保留的行)。 删除这些行,每个组只剩下唯一的一行。

更多的技术说明,你应该如何阅读sql删除语句:

带有别名“a”的表企鹅被加在一个名为别名“b”的企鹅桌子上。 作为子集的右手表“b”查找由foo和bar分组的最大时间戳。 这与左手表“a”相匹配。 (foo,bar,baz)在表格的每一行都有。 右边的子集“b”有一个(maxtimestamp,foo,bar),它只与最左边的那个相匹配。

每个不是最大值的行的值都是NULL的maxtimestamp。 在这些NULL行上过滤,并且你有一组由foo和bar分组的所有行,这不是最新的时间戳baz。 删除那些。

在执行此操作之前先备份表格。

防止这个问题再次发生在这张桌子上:

如果你有这个工作,并把你的“重复行”火。 大。 你的工作还没有完成。 在你的表(在这两列)上定义一个新的复合唯一键,以防止首先添加更多的重复项。 就像一个好的免疫系统一样,在插入的时候甚至不允许坏的行进入桌子。 后来所有这些添加重复的程序都会播出他们的抗议,当你修复它们时,这个问题再也不会出现。

这似乎总是为我工作:

 CREATE TABLE NoDupeTable LIKE DupeTable; INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN; 

其中保留每个愚蠢的最低的身份证和其他非愚蠢的logging。

这是一个简单的答案:

 delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated from target_table GROUP BY field_being_repeated) b on a.field_being_repeated = b.field_being_repeated and a.id_field = b.id_field where b.id_field is null; 
 DELETE FROM table WHERE Field IN (SELECT Field FROM table GROUP BY Field HAVING COUNT(Field) > 1) WHERE SID = "1" 

编辑:

上面的查询将删除所有重复的logging,以保持每一个:

 DELETE FROM table WHERE id NOT IN (SELECT id FROM (SELECT id, field FROM table WHERE SID = "1" GROUP BY field HAVING COUNT(field) > 1) as tmp) AND field in (SELECT DISTINCT field FROM table WHERE SID = "1" GROUP BY field HAVING COUNT(field) > 1) 

我不能完全testing它,但我认为这工作。

此过程将删除表中的所有重复项(包括倍数),保留最后的重复项。 这是检索每个组中最后一条logging的扩展

希望这对某人有用。

 DROP TABLE IF EXISTS UniqueIDs; CREATE Temporary table UniqueIDs (id Int(11)); INSERT INTO UniqueIDs (SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON (T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields AND T1.ID < T2.ID) WHERE T2.ID IS NULL); DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs); 

在自己遇到这个问题之后,在一个庞大的数据库上,我对其他任何答案的performance都不甚满意。 我只想保留最新的重复行,并删除其余的。

在一个查询语句中,没有临时表,这对我来说是最好的,

 DELETE e.* FROM employee e WHERE id IN (SELECT id FROM (SELECT MIN(id) as id FROM employee e2 GROUP BY first_name, last_name HAVING COUNT(*) > 1) x); 

唯一需要注意的是我必须多次运行查询,但即使如此,我发现它比其他选项更适合我。

这个工作为我删除旧logging:

 delete from table where id in (select min(e.id) from (select * from table) e group by column1, column2 having count(*) > 1 ); 

您可以将min(e.id)replace为max(e.id)以删除最新的logging。

 delete p from product p inner join ( select max(id) as id, url from product group by url having count(*) > 1 ) unik on unik.url = p.url and unik.id != p.id; 
 delete from `table` where `table`.`SID` in ( select t.SID from table t join table t1 on t.title = t1.title where t.SID > t1.SID ) 

爱@ eric的答案,但它似乎并不工作,如果你有一个真正的大表(我得到The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay当我尝试运行它)。 所以我限制连接查询只考虑重复的行,我结束了:

 DELETE a FROM penguins a LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo FROM penguins GROUP BY deviceId HAVING num > 1) b ON a.baz != b.keepBaz AND a.foo = b.foo WHERE b.foo IS NOT NULL 

在这种情况下,WHERE子句允许MySQL忽略任何没有重复的行,如果这是重复的第一个实例,也将忽略,所以只有后续的重复将被忽略。 将MIN(baz)更改为MAX(baz)以保留最后一个实例而不是第一个。

这适用于大型表格:

  CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1; DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL; 

删除最早的更改max(id)min(id)

这里这里将列column_name变成主键,同时忽略所有的错误。 因此,它将删除具有column_name重复值的行。

 ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`); 

另一个简单的方法…使用UPDATE IGNORE:

你必须使用一个或多个列索引(types索引)。 创build一个新的临时引用列(不是索引的一部分)。 在本专栏中,您通过使用ignore子句进行更新来标记唯一标识。 一步步:

添加临时参考列以标记唯一身份validation:

 ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`; 

=>这将在你的表中添加一列。

更新表格,尝试将所有内容标记为唯一,但忽略由于重复键入问题而导致的可能错误(logging将被跳过):

 UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1; 

=>您会发现您的重复logging不会被标记为唯一=“是”,换句话说,每组重复logging中只有一个会被标记为唯一。

删除所有不是唯一的东西:

 DELETE * FROM `yourtable` WHERE `unique` <> 'Yes'; 

=>这将删除所有重复logging。

放下列…

 ALTER TABLE `yourtable` DROP `unique`; 

你可以使用DISTINCT子句来select“清理”列表( 这里是一个非常简单的例子)。

如果你计算它们,它可以工作,然后添加一个限制删除查询只留下一个?

例如,如果您有两个或更多,请编写如下所示的查询:

 DELETE FROM table WHERE SID = 1 LIMIT 1; 

从表格中删除重复的数据只需要几个基本步骤:

  • 备份你的桌子!
  • find重复的行
  • 删除重复的行

这里是完整的教程: https : //blog.teamsql.io/deleting-duplicate-data-3541485b3473