【问题标题】:Merge Duplicate Rows in MySQL在 MySQL 中合并重复的行
【发布时间】:2018-11-26 02:56:46
【问题描述】:

我有一个这样的数据库:

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

【问题讨论】:

    标签: mysql


    【解决方案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 值最高的记录之外的所有内容,其中还定义了电话。

    【讨论】:

    • 是否有超过 2 个重复项?例如说有 5 个重复项?
    • 不,它没有,但是你的问题再次没有提到这一点。
    • 是的,抱歉,可能有多个重复项
    • @Jordash 我根据您的新要求更新了我的答案。
    • 你是对的。请记住,我们无法轻松地在本地测试删除查询。
    【解决方案2】:

    这是一个解决方案,它将为您提供结果表中每个用户的每个字段的最新数据,从而满足您的第二个标准以及第一个和第三个标准。根据GROUP_CONCAT 上的group_concat_max_len 条件,它适用于尽可能多的重复项。它使用GROUP_CONCAT 为每个用户准备一个字段的所有值的列表,并进行排序以使最近的值排在第一位。然后使用SUBSTRING_INDEX 提取该列表中的第一个值,这是最新的。此解决方案使用CREATE TABLE ... SELECT 命令创建一个新的users 表,然后DROPs 旧表并将新表重命名为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
    

    输出:

    id  name    email                   phone
    1   bill    bill@fakeemail.com      123456789
    4   john    john@fakeemail.com      987654321
    3   susan   susan@fakeemail.com     (null)
    

    Demo on SQLFiddle

    【讨论】:

    • 如果与其他表有任何关系,删除表用户将失败。
    • @ChristhoferNatalius 同意,但删除行也是如此。
    猜你喜欢
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    • 1970-01-01
    • 2012-08-20
    • 2012-08-31
    • 2019-04-10
    • 2016-02-11
    相关资源
    最近更新 更多