【问题标题】:How to change duplicate rows to unique values in mysql?如何将重复行更改为mysql中的唯一值?
【发布时间】:2012-06-08 23:06:36
【问题描述】:

我有一个包含大约 1M 条记录的数据库表。我需要在此表中找到所有重复的名称并使其唯一。

例如...

Id   Name
-----------
1    A
2    A
3    B
4    C
5    C

应该改为...

Id   Name
-----------
1    A-1
2    A-2
3    B
4    C-1
5    C-2

有没有一种有效的方法通过 mysql 查询或过程来做到这一点?

提前致谢!

【问题讨论】:

    标签: mysql unique


    【解决方案1】:

    这有点棘手。我在本地主机上进行了测试,它可以满足您的需求。如果您有任何问题,请告诉我。 SQL FIDDLE

    UPDATE temp t1, 
    (
        SELECT 
            id as unique_id, 
            new_name 
        FROM(
            SELECT
              id,
              IF(@ROW = Name, @COUNT, @COUNT := 1),
              CONCAT(Name, ' - ', @COUNT) AS new_name,
              @ROW := Name,
              @COUNT := @COUNT + 1
            FROM temp
            JOIN (SELECT @COUNT := 0, @ROW := "") AS t
            WHERE Name IN(SELECT Name FROM temp
            GROUP BY Name
            HAVING COUNT(Name) > 1)
        ) AS temp_test
    ) as testing
    SET t1.Name = testing.new_name where t1.id = testing.unique_id
    

    最终输出如下所示:PICTURE


    编辑: 出于性能考虑,这可能会更好

    1.首先运行此查询

    SET SESSION group_concat_max_len = 1000000;  -- longer if needed
    SET @query1 := (
    SELECT 
        GROUP_CONCAT(DISTINCT unique_name) 
    FROM temp
    JOIN(
        select Name as unique_name
        FROM temp
        GROUP BY name
        HAVING COUNT(Name) > 1
    ) as t
    );
    

    2. 然后运行此更新

    UPDATE temp t1, 
    (
        SELECT 
            id as unique_id, 
            new_name 
        FROM(
            SELECT
              id,
              IF(@ROW = Name, @COUNT, @COUNT := 1),
              CONCAT(Name, ' - ', @COUNT) AS new_name,
              @ROW := Name,
              @COUNT := @COUNT + 1
            FROM temp
            JOIN (SELECT @COUNT := 0, @ROW := "") AS t
            WHERE FIND_IN_SET (`name`, @query1)
        ) AS temp_test
    ) as testing
    SET t1.Name = testing.new_name where t1.id = testing.unique_id
    

    我在我的本地测试了它并且它可以工作,所以你应该能够让它运行:)

    【讨论】:

    • 谢谢,但速度很慢(测试时没有更新,只是选择,10k 数据集超过 10 分钟),这方面还有改进的余地吗?还请包括“更新”语法
    • @Sharky 对不起,我以为我已经包含了更新语法.. 我刚刚做了。根据我的想法来做这个特定的事情,这将与几乎任何其他方法一样快......因为它只更新一次表格,它不应该那么糟糕。意味着它运行一次来​​更改数据库,所以如果它需要的时间比预期的长一点应该没问题。我会考虑尝试优化查询。如果您可以发布查询的解释,以便我们可以看到您如何将其编入索引,这将很有帮助
    • 感谢您的回复,我明天再看看并接受这个:D 是的,我也不相信有改进的余地,因为对于每个更新的行,都必须进行新的选择。 id 上存在索引,name 上不存在。所以选择很快,更新不会重建任何索引。
    • @Sharky 您可以做的一件事是在更新查询之前执行该子选择一次并将其分配给用户定义的变量,然后将该变量放入 IN() ...我在我的手机,所以编写代码并不容易。如果您想等待,我今天晚些时候会回到我的桌面...我想我可以让它工作,它会快得多:)
    • @Sharky 好的,我刚刚更新了我的答案,方法是选择一次重复名称,然后将其插入您的更新查询中。希望这会更快:) 让我知道它是如何工作的! :D
    【解决方案2】:
    UPDATE    table_x AS upd
        SET   upd.Name = CONCAT(upd.Name, '-', upd.Id)
        WHERE upd.id IN(
                        SELECT    sel.id
                            FROM  table_x AS sel
                            WHERE sel.Name = upd.Name
                              AND sel.Id != upd.Id
                     );
    

    【讨论】:

    • 抱歉,我想我忘了提到新的唯一名称,出于安全目的,可能不包含 id。对于每组重复项,该名称必须附加一个以 1 开头的序列号。
    【解决方案3】:

    首先,您应该将重复的 Id 存储在临时表中。


    Drop temporary table if not exist temp;
    

    Create temporary table temp (
    Select max(id)'id' from table_x group by Name having count(*)>1
    );
    

    Delete from table_x as x,temp as t where x.id = t.id;
    

    重复执行此操作...在将唯一键设置为名称字段后,您将获得唯一行..

    【讨论】:

      【解决方案4】:

      一个可读的解决方案

      CREATE TEMPORARY TABLE duplicate_names
      SELECT name FROM records_table
      GROUP BY name
      HAVING count(name) > 1;
      
      SET @row_number = 1;
      SET @name = '';
      CREATE TEMPORARY TABLE duplicates
      SELECT 
      CASE 
      WHEN @name = name THEN @row_number:=@row_number + 1
        ELSE   
          @row_number:=1 
      END AS identifier,
      @name:=name AS name,id 
      FROM
          records_table WHERE name IN (SELECT name FROM duplicate_names)
      ORDER BY records_table.name;
          
      UPDATE records_table INNER JOIN duplicates 
      ON records_table.id = duplicates.id
      SET records_table.name = 
      CONCAT(duplicates.name,'-',duplicates.identifier);
      

      【讨论】:

        猜你喜欢
        • 2015-09-29
        • 1970-01-01
        • 2014-01-12
        • 2021-07-13
        • 1970-01-01
        • 2018-06-04
        • 1970-01-01
        • 2020-02-25
        • 1970-01-01
        相关资源
        最近更新 更多