MYSQL重复数据消除并删除数据最少的重复行

MYSQL重复数据消除并删除数据最少的重复行,mysql,Mysql,我正在开发一个MYSQL数据库,它有以下三列:电子邮件、姓名、姓氏 我需要做的是消除电子邮件中的重复数据,我知道我可以使用这样的功能(此查询只是为了排序而不是删除): 或 但是,我还需要确保,当发现重复的电子邮件地址时,保留的是具有名称和/或姓氏值的电子邮件地址 例如: |id |电子邮件|姓名|姓氏| |1 | bob@bob.com|鲍勃|保尔森| |2 | bob@bob.com||| 在这种情况下,我希望保留第一个结果并删除第二个结果 我一直在研究使用“case”或“if”语句,但没有使

我正在开发一个MYSQL数据库,它有以下三列:电子邮件、姓名、姓氏

我需要做的是消除电子邮件中的重复数据,我知道我可以使用这样的功能(此查询只是为了排序而不是删除):

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

例如:

|id |电子邮件|姓名|姓氏|
|1 | bob@bob.com|鲍勃|保尔森|
|2 | bob@bob.com|||

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

我一直在研究使用“case”或“if”语句,但没有使用这些语句的经验。我尝试用这些语句扩展上述函数,但没有成功

谁能给我指一下正确的方向吗

PS:表中的第一列是一个自动递增的id值,以防万一

更新1:到目前为止,下面的@Bohemian答案效果很好,但在一个重复电子邮件地址的情况下失败了,其中一行有名字但没有姓氏,下一行没有名字但有姓氏。它将保留这两项记录。所有需要编辑的是,这两条记录中的一条被删除,不管是哪条记录

更新2:@Bohemian的答案很好,但经过更多测试后,我发现它有一个根本性的缺陷,即它只有在名称和姓氏字段包含数据的重复电子邮件行(如上表中的第一个条目)时才起作用。如果有重复的电子邮件,但没有一行同时填写了姓名和姓氏字段,那么所有这些行都将被忽略,不会消除重复

此查询的最后一步是确定如何删除不符合当前必要条件的重复项。如果一行只有名字,另一行只有姓氏,那么删除哪一行并不重要,因为电子邮件是最重要的保留内容。

mysql很容易做到这一点:


您可以使用此删除查询,它是通用的,可以轻松地进行调整以支持更多字段:

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
请看小提琴

此查询返回每个电子邮件的最大非空字段数:

SELECT
  emails,
  MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls
FROM
  tablename
GROUP BY
  emails
然后,我将使用tablename加入此查询,以获取每个具有最大非空字段数的电子邮件的最小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的行。

删除具有重复电子邮件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
    )

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

当一行有名称,下一行有姓氏时,需要做什么?这是您要经常做的事情还是只是一次性修复?在这种情况下,我认为最好的解决方案是将这两行连接起来,虽然我认为这会使事情复杂化。这是一次性的,但可能会在数据库更新时每月使用一次来清除数据库。非常感谢@Bohemian,查询工作得很好。唯一不起作用的情况是,一行重复的电子邮件有名称但没有姓氏,而另一行没有名称但有用户名。在这种情况下,两者都保留。在这种情况下,保留哪一个并不重要,但必须保留。是的,有一个轻微的逻辑错误-但很容易修复;-)@草莓你愿意分享你想要的修复方法吗?我刚刚还注意到,如果有一个重复的行,并且两行都没有名字或姓氏,那么它们都会被保留。非常感谢你,查询工作非常完美。同时也感谢您对所采取步骤的解释,这非常有帮助。我能给你一杯啤酒吗?
SELECT
  emails,
  MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls
FROM
  tablename
GROUP BY
  emails
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
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
    )