【问题标题】:MYSQL remove duplicates from table with two columnsMYSQL 从具有两列的表中删除重复项
【发布时间】:2020-02-19 05:57:02
【问题描述】:

有表contents_tags

+------------+--------+
| content_id | tag_id |
+------------+--------+
|          1 |      1 |
|          1 |      2 |
|          1 |      2 |
|          2 |      3 |
|          2 |      4 |
|          2 |      4 |

我想用两列创建唯一索引

alter table contents_tags ADD UNIQUE `contents_tags` (`content_id`, `tag_id`);

但我已经有重复的条目并收到错误:

错误 1062 (23000):键“contents_tags”的重复条目“1-2”

alter IGNORE table contents_tags ADD UNIQUE `contents_tags` (`content_id`, `tag_id`);

忽略 - 在 Mysql 8 中不起作用

如何删除重复项?

【问题讨论】:

    标签: mysql


    【解决方案1】:

    您必须首先删除除唯一值之外的所有值。其中一个选项是使用 intermediate 表。

    CREATE TABLE tmp 
    AS SELECT DISTINCT content_id, tag_id FROM contents_tags;
    
    TRUNCATE contents_tags;
    
    INSERT INTO contents_tags SELECT * FROM tmp;
    
    DROP TABLE tmp;
    

    https://www.db-fiddle.com/f/j6T6PXHvGF8V9HbFfiompk/0

    【讨论】:

    • 注意:要创建临时表,您应该使用CREATE TEMPORARY TABLE
    • 我会将“应该”替换为“可以”;)“真实”临时表有大小限制,不是吗? @TimBiegeleisen
    • 好点,而且创建临时表可能会占用大量服务器内存,这并不总是一件好事。也许称它为“中间”表或类似的东西:-)
    • 最好将tmp 定义为 TEMPORARY - 它会在连接关闭期间自动删除(不需要显式 DROP)。而且,如果最终表数据不是很大,那么将这个表定义为ENGINE=Memory 对磁盘写入最小化很有用。
    • @Akina 我会留下答案,但我希望亚历克斯会认为 cmets 是有用的。关于临时表限制:dev.mysql.com/doc/refman/8.0/en/temporary-table-problems.html
    【解决方案2】:

    你可以试试下面-

    DELETE FROM contents_tags 
    WHERE 
        content_id IN (
        SELECT 
            content_id
        FROM (
            SELECT 
                content_id,
                ROW_NUMBER() OVER (
                    PARTITION BY content_id,tag_id 
                    ORDER BY content_id,tag_id) AS row_num
            FROM 
                contents_tags 
    
        ) t
        WHERE row_num > 1
    );
    

    【讨论】:

    • 所有重复记录将被删除。
    【解决方案3】:

    如果您要在作为整个表的两列上创建一个唯一键,它也可能是主键:

    CREATE TABLE contents_tags2 (
      `content_id` INTEGER,
      `tag_id` INTEGER,
      PRIMARY KEY (`content_id`,  `tag_id`)
      );
    
    INSERT INTO  contents_tags2 SELECT DISTINCT content_id, tag_id FROM contents_tags;
    
    RENAME TABLE contents_tags TO contents_tags_del, contents_tags2 TO contents_tags;
    
    DROP TABLE contents_tags_del;  
    

    fiddle

    【讨论】:

    • 如果存在某些外键,重命名将失败(如果 FK 可能非唯一 - 不记得了)。如果存在,anycase 触发器将丢失。
    【解决方案4】:

    如果您可以放下桌子,还有另一种方法。

    IGNOREALTER TABLE 的支持已从5.6 版本中弃用,如果我没记错的话。但是你仍然可以在INSERT 中使用IGNORE

    CREATE TABLE contents_tags_new LIKE contents_tags;
    
    ALTER TABLE contents_tags_new ADD UNIQUE INDEX (content_id ,tag_id );
    
    INSERT IGNORE INTO contents_tags_new SELECT * FROM contents_tags;
    
    DROP TABLE contents_tags;
    
    RENAME TABLE contents_tags_new TO contents_tags;
    

    CHECK DEMO HERE

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多