在MySQL中合并重复的行

时间:2018-11-26 02:56:47

标签: mysql

我有一个这样的数据库:

users
id    name    email                phone
1     bill    bill@fakeemail.com
2     bill    bill@fakeemail.com   123456789
3     susan   susan@fakeemail.com
4     john    john@fakeemail.com   123456789
5     john    john@fakeemail.com   987654321

我想根据电子邮件字段合并被视为重复的记录。

试图弄清楚如何使用以下注意事项。

  1. 基于重复的电子邮件进行合并
  2. 如果一行的值为空,则使用数据最多的行。
  3. 如果2行重复,但其他字段不同,则使用

具有最高ID的号码(有关示例,请参见john@fakeemail.com行。)

这是我尝试过的查询:

DELETE FROM users WHERE users.id NOT IN 
(SELECT grouped.id FROM (SELECT DISTINCT ON (email) * FROM users) AS grouped)

获取语法错误。

我正在尝试将数据库转换为此,我无法找出正确的查询:

users
id   name    email                 phone
2    bill    bill@fakeemail.com    123456789
3    susan   susan@fakeemail.com   
5    john    john@fakeemail.com    987654321

2 个答案:

答案 0 :(得分:1)

以下是使用删除联接的一种选择:

DELETE
FROM users
WHERE id NOT IN (SELECT id
                 FROM (
                     SELECT CASE WHEN COUNT(*) = 1
                                 THEN MAX(id)
                                 ELSE MAX(CASE WHEN phone IS NOT NULL THEN id END) END AS id
                     FROM users
                     GROUP BY email) t);

此删除的逻辑如下:

  • 只有一条记录的电子邮件不会被删除
  • 对于具有两个或多个记录的电子邮件,我们会删除除id值最高的记录(其中也定义了电话)之外的所有内容。

答案 1 :(得分:1)

这是一个解决方案,它将为您提供结果表中每个用户每个字段的最新数据,从而满足您的第二个条件以及第一个和第三个条件。根据{{​​1}}上的group_concat_max_len条件,它可以处理尽可能多的重复项。它使用GROUP_CONCAT为每个用户准备一个字段的所有值的列表,并对其进行排序,以使最新值在前。然后使用SUBSTRING_INDEX提取该列表中的第一个值,这是最新的。此解决方案使用CREATE TABLE ... SELECT命令创建一个新的GROUP_CONCAT表,然后users替换旧表并将新表重命名为DROP

users

输出:

CREATE TABLE users
    (`id` int, `name` varchar(5), `email` varchar(19), `phone` int)
;

INSERT INTO users
    (`id`, `name`, `email`, `phone`)
VALUES
    (1, 'bill', 'bill@fakeemail.com', 123456789),
    (2, 'bill', 'bill@fakeemail.com', NULL),
    (3, 'susan', 'susan@fakeemail.com', NULL),
    (4, 'john', 'john@fakeemail.com', 123456789),
    (5, 'john', 'john@fakeemail.com', 987654321)
;

CREATE TABLE newusers AS
SELECT id
     , SUBSTRING_INDEX(names, ',', 1) AS name
     , email
     , SUBSTRING_INDEX(phones, ',', 1) AS phone
FROM (SELECT id
           , GROUP_CONCAT(name ORDER BY id DESC) AS names
           , email
           , GROUP_CONCAT(phone ORDER BY id DESC) AS phones
      FROM users
      GROUP BY email) u;

DROP TABLE users;

RENAME TABLE newusers TO users;

SELECT * FROM users

Demo on SQLFiddle