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

psy*_*lus 5 mysql

我正在使用具有以下三列的MYSQL数据库:电子邮件,姓名,姓氏。

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

select distinct emails, name, surname from emails;
Run Code Online (Sandbox Code Playgroud)

要么

select emails, name, surname from emails group by emails having count(*) >= 2;
Run Code Online (Sandbox Code Playgroud)

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

例如:

| id | 电子邮件| 名称| 姓|
| 1 | bob@bob.com | 鲍勃 保罗|
| 2 | bob@bob.com | | |

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

我一直在研究使用“ case”或“ if”语句,但是对使用这些语句没有经验。我尝试使用这些语句扩展上述功能,但无济于事。

有人能指出我正确的方向吗?

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

更新1:到目前为止,下面的@Bohemian答案有效,但在一种情况下失败,即重复的电子邮件地址在其中一行中有一个名字但没有姓氏,而在下一行中它没有名称但有姓氏。它将保留两个记录。所有需要编辑的就是无论哪一条记录都将被删除。

更新2:@Bohemian的答案很好,但经过更多测试,我发现它有一个根本性的缺陷,即只有当重复的电子邮件行中名称和姓氏字段具有数据(例如上表)。如果电子邮件重复,但没有任何行同时填写名称和姓氏字段,则所有这些行都将被忽略并且不会重复数据删除。

该查询的最后一步是弄清楚如何删除不符合当前必要条件的重复项。如果其中一行仅包含姓名,另一行仅包含姓氏,那么删除哪一行实际上并不重要,因为保留电子邮件是重要的事情。

fth*_*lla 4

您可以使用此 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
Run Code Online (Sandbox Code Playgroud)

请参阅此处的小提琴。

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

SELECT
  emails,
  MAX((name IS NOT NULL) + (surname IS NOT NULL)) max_non_nulls
FROM
  tablename
GROUP BY
  emails
Run Code Online (Sandbox Code Playgroud)

然后,我将此查询与表名连接起来,以获取具有最大非空字段数的每封电子邮件的最小 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
Run Code Online (Sandbox Code Playgroud)

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