【问题标题】:MySQL removing Duplicate Rows with Primary KeyMySQL使用主键删除重复行
【发布时间】:2015-07-03 22:00:38
【问题描述】:

我有一个包含以下列的表格:

ID(primary key),
USER,
ACTION
TIME
LOCATION

我正在尝试删除重复的条目,同时使用以下列:USER, ACTION, TIME, LOCATION

我写了以下查询:

DELETE FROM test.testlogins  
WHERE id IN (SELECT * 
             FROM (SELECT id FROM test.testlogins 
                   GROUP BY USER, ACTION, TIME, LOCATION HAVING (COUNT(*) > 1)
                  ) AS A
            );

但是,当我执行它时,每次运行我只会删除 1 行。我的测试数据大约有 40 多行重复,每行都分配了一个单独的 id

【问题讨论】:

    标签: mysql sql primary-key


    【解决方案1】:
    DELETE t1.*
    FROM
      testlogins t1 INNER JOIN testlogins t2
      ON t1.user=t2.user
         AND t1.action=t2.action
         AND t1.time=t2.time
         AND t2.location=t2.location
         AND t1.id>t2.id
    

    如果要保留 ID 最小的行,可以使用 t1.id>t2.id,如果要保留 ID 最大的行,可以使用 t1.id<t2.id

    【讨论】:

    • 这按预期工作(删除了多个重复项),但我也将尝试使用它作为触发器,以防止在添加重复项时发生同样的情况。关于如何防止添加重复项的任何想法。
    • @silverzpeed 你应该用CREATE UNIQUE INDEX idx_userlogins ON testlogins (USER, ACTION, TIME, LOCATION)创建一个唯一索引
    • 我在删除服务器上有一个脚本,它构建一个插入脚本并执行插入。如果有重复,我在日志中看到的错误输出会影响插入吗?
    • @silverzpeed 请参阅我的其他答案。是的,如果存在唯一索引,则在插入重复项时会出现错误...您可以使用 INSERT .. ON DUPLICATE ... 语法忽略重复的插入而不会引发错误
    【解决方案2】:

    最简单的解决方案是使用ALTER IGNORE 向表中添加唯一索引。如果表大小不是很大,这将避免将来出现此问题。

    ALTER IGNORE TABLE testlogins ADD UNIQUE KEY (USER, ACTION, TIME, LOCATION)
    

    使用新的唯一索引在其他数据库中创建一个新表,并使用 INSERT IGNORE 将所有数据加载到新表中

    【讨论】:

      【解决方案3】:

      编写此查询的另一种方法是:

      DELETE tl
          FROM test.testlogins tl LEFT JOIN
               (SELECT MIN(id) as id
                FROM test.testlogins 
                GROUP BY USER, ACTION, TIME, LOCATION
               ) tokeep
               ON tl.id = tokeep.minid
          WHERE tokeep.id IS NULL;
      

      大概,您一次只删除一个 id 的原因是因为您的语句中的 group by 只返回一个 id - 这就是您要删除的那个。如果一个列组合出现 40 次,则您仅删除该组中每个 delete 的一个 id。

      另一方面,此方法查找要保留的行(任意具有最小id 的行)。然后,它会删除其他所有内容。

      【讨论】:

        【解决方案4】:
        DELETE FROM testlogins  
        WHERE EXISTS ( SELECT 'a'
                       FROM testlogins t2
                       WHERE t2.USER = testlogins.USER
                       AND t2.ACTION= testlogins.ACTION
                       AND t2.TIME = testlogins.TIME 
                       AND t2.LOCATION = testlogins.LOCATION 
                       AND t2.ID > testlogins.ID
                      )
        

        删除所有具有相同属性且最大 id 较低的行

        【讨论】:

        • 这在 MySQL 中不起作用,因为子查询无法引用正在删除行的表。
        猜你喜欢
        • 2017-02-12
        • 2015-06-14
        • 2020-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-03
        • 2014-11-29
        • 1970-01-01
        相关资源
        最近更新 更多