2013-08-01 161 views
4

我正在处理一个MYSQL数据库,它有以下三列:电子邮件,姓名,姓氏。MYSQL重复删除重复行并删除重复行数据最少

我需要做的就是重复数据删除,我知道我可以使用的功能,如这一个(这个查询只是排序未删除)的邮件:

select distinct emails, name, surname from emails; 

select emails, name, surname from emails group by emails having count(*) >= 2; 

不过,我还需要确保在发现重复的电子邮件地址时,保留的电子邮件地址是具有名称和/或姓氏值的电子邮件地址。

例如:

| id |电子邮件                            |名称|姓氏
| 1 | [email protected] |鲍勃        |保尔森      |
| 2 | [email protected] |                       |                                   |

在这种情况下,我想保留第一个结果并删除第二个。

我一直在寻找使用'案例'或'如果'的陈述,但没有经验与使用这些。我试图用这些陈述扩展上述功能,但无济于事。

任何人都可以指向正确的方向吗?

PS:表中的第一列是自动增加一个ID值,如果可以帮助

更新1:下面到目前为止@Bohemian答案是伟大的工作,但在一种情况下发生故障,其中有一个重复电子邮件地址在一行中有一个名字,但没有姓,在下一行它没有名字,但有一个姓。它将保留这两个记录。所有需要编辑的内容都是为了让这两个记录中的一个被删除,不管是哪一个。

更新2:@波希米亚的答案很好,但经过更多测试后,我发现它存在一个根本性的缺陷,它只在存在重复的电子邮件行时名称和姓氏字段有数据上表中的第一项)。如果电子邮件重复,但所有行都没有填写名称和姓氏字段,则所有这些行都将被忽略,并且不会进行重复数据删除。

此查询的最后一步是找出如何删除不符合当前必要条件的重复项。如果一行只有名字而另一行只是姓氏,那么删除它并不重要,因为电子邮件是重要的事情。

+1

当一行有名字和下一个姓氏时需要做什么? –

+0

这是你打算定期做的事情,还是只是一次性修复? – martin

+0

在这种情况下,我会认为最好的解决方案是将两者连接起来,尽管我认为这会使问题变得复杂。 – psychedelus

回答

3

您可以使用此DELETE查询,这是通用的,可以很容易地适应以支持更多的领域:

DELETE tablename.* 
FROM 
    tablename LEFT JOIN (
    SELECT MIN(id) min_id 
    FROM 
     tablename t INNER JOIN (
     SELECT 
      emails, MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls 
     FROM 
      tablename 
     GROUP BY 
      emails) m 
     ON t.emails=m.emails 
     AND ((t.name IS NOT NULL) + (t.surname IS NOT NULL))=m.max_non_nulls 
    GROUP BY 
     t.emails) ids 
    ON tablename.id=ids.min_id 
WHERE 
    ids.min_id IS NULL 

请参阅小提琴here

该查询返回非空字段的最大数目,每封电子邮件:

SELECT 
    emails, 
    MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls 
FROM 
    tablename 
GROUP BY 
    emails 

然后我加入这个查询与表名,获得最小的ID为拥有最大数量的每封电子邮件非空字段:

SELECT MIN(id) min_id 
FROM 
    tablename t INNER JOIN (
    SELECT 
     emails, MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls 
    FROM 
     tablename 
    GROUP BY 
     emails) m 
    ON t.emails=m.emails 
    AND ((t.name IS NOT NULL) + (t.surname IS NOT NULL))=m.max_non_nulls 
GROUP BY 
    t.emails 

然后我删除所有具有此查询未返回的ID的行。

+0

非常感谢你,查询完美地工作。也很感谢你采取的步骤的解释,它有很大的帮助。任何方式,我可以捐赠给你一杯啤酒? – psychedelus

4

这是很容易与MySQL的multiple-table delete syntax

delete b 
from mytable a 
join mytable b 
    on a.email = b.email 
    and a.id != b.id 
where a.name is not null 
and a.surname is not null 
+1

非常感谢@Bohemian,查询效果很好。唯一不起作用的情况是,一行中有重复的电子邮件有名字而没有姓,另一行没有名字但有一个用户名。在这种情况下,两者都保留。在这种情况下,保存的内容并不重要,但必须去做。 – psychedelus

+0

是的,这里有一个轻微的逻辑错误 - 但它很容易修复;-) – Strawberry

+1

@Strawberry你愿意分享你想要的修复吗? – psychedelus

0

删除记录重复的电子邮件ID

delete 
    from duplicate_email where id in(
     select id from (
      select id, email from duplicate_email group by email having count(id) > 1) as id 
    ) 

,但有一个问题,你可以删除那些只有一个重复的电子邮件即,两个相同的电子邮件,但如果有三个或更多,你可以重复记录这个查询,直到你得到零记录删除