仅保留最早的行,删除重复的行?

13

我有一张数据表,其中包含许多用户提交的重复条目。

我想根据字段subscriberEmail删除所有重复行,只保留原始提交。

换句话说,我想查找所有重复的电子邮件,并删除这些行,只保留原始数据。

如何在不交换表的情况下执行此操作?
我的表中包含每行的唯一标识符。


你应该将一个答案标记为“已接受” :-) - watery
3个回答

27

因为您将id列用作指示哪条记录是“原始”的标识符:

delete x 
from myTable x
 join myTable z on x.subscriberEmail = z.subscriberEmail
where x.id > z.id

这将每个电子邮件地址留下一条记录。

编辑以添加:

解释上面的查询...

这里的想法是将表与自身连接。假设您有两份表副本,每个副本都有不同的名称。然后您可以将它们相互比较,并找到每个电子邮件地址的最低ID。接着,您将看到稍后创建的重复记录并可删除它们。(我在思考时想象着Excel)

为了在表上执行该操作,将其与自身进行比较并能够识别每个方向,需要使用表别名。x是表别名。它在from子句中分配,如下所示:from <table> <alias>。现在可以在同一查询中的其他位置使用x作为对该表的引用的快捷方式。

delete x从我们的动作和目标开始了查询。我们将执行一个从多个表中选择记录的查询,并希望删除出现在x中的记录。

别名用于引用该表的两个“实例”。from myTable x join myTable z on x.subscriberEmail = z.subscriberEmail 将表与自身相结合,其中电子邮件匹配。如果没有随后的where子句,任何记录都会被选中,因为它可以与自身连接。

where子句限制了所选记录。where x.id > z.id 使'x'别名的“实例”仅包含匹配电子邮件但具有更高id值的记录。您真正想要的数据,即唯一的电子邮件地址(带有最低的Id),将不是x的一部分,也不会被删除。x中的唯一记录将是具有较高ID的重复记录(电子邮件地址)。

在这种情况下,连接和where子句可以合并:

delete x 
  from myTable x 
  join myTable z
    on x.subscriberEmail = z.subscriberEmail
      and x.id > z.id

为了防止重复,考虑将subscriberEmail列设为唯一索引列。


嘿,我不明白这里的X是什么,以及日期在哪里输入。由于每个都有主ID设置,我可以使用ID,或者日期。ID听起来更容易。 - RB. J
嘿,它起作用了!!!我将“createdOn”更改为“id”,然后就完成了!哈哈,谢谢 - 这是我在PHP中使用的代码:mysql_query("delete x from my_Table x join my_Table z on x.subscriberEmail = z.subscriberEmail where x.id > z.id") or die (mysql_error()); - RB. J
你能解释一下如何用英语阅读这段代码吗?理解语法需要有逻辑阅读的能力。另外,我该如何在一开始就避免重复?我已经使用了Insert IGNORE,但它并没有忽略重复项。 - RB. J
1
@RB 我几天前更新了答案,您能否告诉我它是否有帮助并接受答案?或者让我知道您还需要什么? - Fosco
为了扩展上述内容 - 相同的示例可用于选择除一个之外的所有重复项。只需要将 "delete" 替换为 "select": "select distinct x.* from cdrs_01 x join cdrs_01 z on x.stamp = z.stamp where x.id > z.id;" - Vladimir Kroz

1
现在你不需要使用自连接来创建任何临时表了。
DELETE u1 FROM users u1, users u2 WHERE u1.id < u2.id AND u1.email = u2.email

检查表中是否存在重复记录

SELECT count(*) as Count, email FROM users u group by email having Count > 1

0
如果每行都有唯一的ID,您可以尝试像这样的操作。不要问我为什么需要第二个select语句,否则mysql将不允许我执行。此外,请按照使结果唯一的任何列进行分组。
delete from my_table where id in (
  select id from (
    select id from my_table a group by subscriberEmail having count(*) > 1
  ) b
);

1
我相信这将删除所有内容,而不仅仅是额外的。 - Fosco
不会的。按subscriberEmail分组将像行分组。因此,具有多个电子邮件的订阅者将被选择(具有count(*)> 1)。此时,您几乎拥有具有多个电子邮件的订阅者的唯一记录集。从该记录集中获取ID并将其删除。我尝试过了,它非常有效。 - Brad G
运行此代码会产生错误 "#1064 - 您的SQL语法有误;请检查与您的MySQL服务器版本相对应的手册,以获取正确的语法使用方式,在第2行附近" - 以下是代码 - RB. J
mysql_query("DELETE from my_table where id in ( select id from ( select id from my_table a group by subscriberEmail having count(*) > 1 ) b") or die (mysql_error()); - RB. J
你把“my_table”替换成了你的表名了吗?你的表上的主键真的叫做“id”吗?调整一下,使其适用于你的数据库,我只是写了一个通用的代码。 - Brad G
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接