【问题标题】:How to delete duplicate records in mysql database?如何删除mysql数据库中的重复记录?
【发布时间】:2010-10-14 04:18:48
【问题描述】:

使用 rails 或 mysql 查询删除 mysql 数据库中重复记录的最佳方法是什么?

【问题讨论】:

  • 您需要一个关键字段来查找以使记录与众不同,这样您就可以知道要删除什么

标签: mysql ruby-on-rails ruby


【解决方案1】:
Delete t1 from table1 inner join table1 t2 where t1.id < t2.id and t1.name = t2.name

更多详情请查看以下 YouTube 链接:

https://youtu.be/cNGktcS_qGU

【讨论】:

    【解决方案2】:

    首先对要删除重复项的列进行分组。但我没有使用分组。我正在写自我加入。

    您不需要创建临时表。

    删除除一条记录之外的重复项: 在这个表中它应该有自动增量列。 我刚刚遇到的可能的解决方案:

    DELETE n1 FROM names n1, names n2 WHERE n1.id > n2.id AND n1.name = n2.name
    

    如果您想保留自动增量 id 值最低的行或

    DELETE n1 FROM names n1, names n2 WHERE n1.id < n2.id AND n1.name = n2.name
    

    如果您想保留具有最高自动增量 id 值的行。

    您可以交叉检查您的解决方案,再次找到重复项:

    SELECT * FROM `names` GROUP BY name, id having count(name) > 1;
    

    如果返回0结果,则查询成功。

    【讨论】:

      【解决方案3】:

      这是我想出的 Rails 解决方案。可能不是最有效的,但如果是一次性迁移,则没什么大不了的。

      distinct_records = MyTable.all.group(:distinct_column_1, :distinct_column_2).map {|mt| mt.id}
      duplicates = MyTable.all.to_a.reject!{|mt| distinct_records.include? mt.id}
      duplicates.each(&:destroy)
      

      首先,按确定唯一性的所有列分组,示例显示 2,但您可以有更多或更少

      其次,选择该组的倒数...所有其他记录

      第三,删除所有这些记录。

      【讨论】:

        【解决方案4】:

        我使用上面@krukid 的答案在大约 70,000 个条目的表格上执行以下操作:

        rs = 'select a, b, count(*) as c from table group by 1, 2 having c > 1'
        
        # get a hashmap
        dups = MyModel.connection.select_all(rs)
        
        # convert to array
        dupsarr = dups.map { |i|  [i.a, i.b, i.c] }
        
        # delete dups
        dupsarr.each do |a,b,c|
            ActiveRecord::Base.connection.execute("delete from table_name where a=#{MyModel.sanitize(a)} and b=#{MyModel.sanitize(b)} limit #{c-1}")
        end
        

        【讨论】:

          【解决方案5】:

          假设我们有一个表名 tbl_product 并且在字段 p_pi_codep_nats_id 的最大计数中存在重复 首先创建一个新表,从现有表中插入数据...
          即从 tbl_productnewtable1,如果还有其他内容,则从 newtable1newtable2

          CREATE TABLE `newtable2` (                                  
                      `p_id` int(10) unsigned NOT NULL auto_increment,         
                      `p_status` varchar(45) NOT NULL,                         
                      `p_pi_code` varchar(45) NOT NULL,                        
                      `p_nats_id` mediumint(8) unsigned NOT NULL,              
                      `p_is_special` tinyint(4) NOT NULL,                      
                       PRIMARY KEY (`p_id`)                                   
                ) ENGINE=InnoDB;
          
          INSERT INTO newtable1 (p_status, p_pi_code, p_nats_id, p_is_special) SELECT 
              p_status, p_pi_code, p_nats_id, p_is_special FROM tbl_product group by p_pi_code;
          
          INSERT INTO newtable2 (p_status, p_pi_code, p_nats_id, p_is_special) SELECT 
              p_status, p_pi_code, p_nats_id, p_is_special FROM newtable1 group by p_nats_id;
          

          之后我们看到该字段中的所有重复项都被删除了

          【讨论】:

            【解决方案6】:

            我正在使用Alter Table

            ALTER IGNORE TABLE jos_city ADD UNIQUE INDEX(`city`);
            

            【讨论】:

            • 这似乎不起作用,让我ERROR 1062 (23000): Duplicate entry '14190-2089' for key 'vid'
            • 这绝对不会删除现有的重复,只会阻止插入新的
            【解决方案7】:

            如果您在表 (EMP) 中有 PK (id) 并且想要较旧地删除具有名称列的重复记录。对于大数据,以下查询可能是不错的方法。

            DELETE t3
            FROM (
                    SELECT t1.name, t1.id
                    FROM (
                            SELECT name
                            FROM EMP
                            GROUP BY name
                            HAVING COUNT(name) > 1
                    ) AS t0 INNER JOIN EMP t1 ON t0.name = t1.name
            ) AS t2 INNER JOIN EMP t3 ON t3.name = t2.name
            WHERE t2.id < t3.id;
            

            【讨论】:

              【解决方案8】:

              检查重复条目:

              SELECT DISTINCT(req_field) AS field, COUNT(req_field) AS fieldCount FROM 
              table_name GROUP BY req_field HAVING fieldCount > 1
              


              删除重复查询:

              DELETE FROM table_name 
              USING table_name, table_name AS vtable 
              WHERE 
                  (table_name.id > vtable.id) 
              AND (table_name.req_field=req_field)
              

              替换 req_fieldtable_name - 应该可以正常工作。

              【讨论】:

              • 在 postgres 中,这应该是 DELETE FROM table_name USING table_name AS vtable WHERE (table_name.id &gt; vtable.id) AND (table_name.req_field=req_field)
              【解决方案9】:

              在 MySql 中,当我放置类似

              的内容时
              delete from A where IDA in (select IDA from A )
              

              mySql 说了类似“你不能在删除操作的选择部分使用同一张表。”

              我只需要删除一些重复的记录,并且我已经成功使用了类似的 .php 程序

              <?php
              ...
              $res = hacer_sql("SELECT MIN(IDESTUDIANTE) as IDTODELETE 
              FROM `estudiante` group by `LASTNAME`,`FIRSTNAME`,`CI`,`PHONE`
              HAVING COUNT(*) > 1 )");
              while ( $reg = mysql_fetch_assoc($res) ) {
                 hacer_sql("delete from estudiante where IDESTUDIANTE = {$reg['IDTODELETE']}");
              }
              ?>
              

              【讨论】:

                【解决方案10】:

                这是另一个没有特定语言的想法:

                rs = `select a, b, count(*) as c from entries group by 1, 2 having c > 1`
                rs.each do |a, b, c|
                  `delete from entries where a=#{a} and b=#{b} limit #{c - 1}`
                end
                

                编辑:

                感谢Olaf 的“有”提示:)

                【讨论】:

                • 确实没有特定的语言;)
                • 您将需要在您的删除语句中使用 order by 子句,否则无法保证保留哪个组。
                • @Dave 没错,如果这对您的特定任务很重要,您应该指定一个订单列。
                【解决方案11】:

                如果您的表有一个 PK(或者您可以轻松地给它一个),您可以使用以下查询指定表中任意数量的列相等(限定为重复)(可能有点乱看起来但它有效):

                DELETE FROM table WHERE pk_id IN(
                   SELECT DISTINCT t3.pk_id FROM (
                       SELECT t1.* FROM table AS t1 INNER JOIN (
                           SELECT col1, col2, col3, col4, COUNT(*) FROM table
                           GROUP BY col1, col2, col3, col4 HAVING COUNT(*)>1) AS t2
                       ON t1.col1 = t2.col1 AND t1.col2 = t2.col2 AND t1.col3 = t2.col3 AND
                       t1.col4 = t2.col4)
                   AS t3, (
                       SELECT t1.* FROM table AS t1 INNER JOIN (
                           SELECT col1, col2, col3, col4, COUNT(*) FROM table
                           GROUP BY col1, col2, col3, col4 HAVING COUNT(*)>1) AS t2
                       ON t1.col1 = t2.col1 AND t1.col2 = t2.col2 AND t1.col3 = t2.col3 AND
                       t1.col4 = t2.col4)
                   AS t4
                   WHERE t3.col1 = t4.col1 AND t3.pk_id > t4.pk_id
                

                )

                这将保留输入数据库的第一条记录,删除“最新”重复项。如果要保留最后一条记录,请将 > 切换为

                【讨论】:

                  【解决方案12】:

                  SQL 新手 :-) 这是一个经典问题——在面试中经常被问到:-) 我不知道它是否适用于 MYSQL,但它适用于大多数数据库 -

                  > create table t(
                  >     a char(2),
                  >     b char(2),
                  >     c smallint )
                  
                  > select a,b,c,count(*) from t
                  > group by a,b,c
                  > having count(*) > 1
                  a  b  c
                  -- -- ------ -----------
                  (0 rows affected)
                  
                  > insert into t values ("aa","bb",1)
                  (1 row affected)
                  
                  > insert into t values ("aa","bb",1)
                  (1 row affected)
                  
                  > insert into t values ("aa","bc",1)
                  (1 row affected)
                  
                  > select a,b,c,count(*) from t group by a,b,c having count(*) > 1
                  a  b  c 
                  -- -- ------ -----------
                  aa bb      1           2
                  (1 row affected)
                  

                  【讨论】:

                  • 格式丢失了 - 但我很确定任何程序员都能够弄清楚。
                  • 我已经更正了格式。即使您回答了如何“选择”nan 想要“删除”它们的记录,但现在它更容易阅读,而且答案无论如何都与潜在问题有关。
                  • 非常感谢这个查询非常有效:D > select a,b,c,count() from t group by a,b,c with count() > 1
                  【解决方案13】:

                  你可以使用:

                  http://lenniedevilliers.blogspot.com/2008/10/weekly-code-find-duplicates-in-sql.html

                  获取重复项,然后通过 Ruby 代码或 SQL 代码删除它们(我会在 SQL 代码中执行,但这取决于你 :-)

                  【讨论】:

                    【解决方案14】:

                    好吧,如果它是一张小桌子,你可以从 rails 控制台做

                    class ActiveRecord::Base
                      def non_id_attributes
                        atts = self.attributes
                        atts.delete('id')
                        atts
                      end
                    end
                    
                    duplicate_groups = YourClass.find(:all).group_by { |element| element.non_id_attributes }.select{ |gr| gr.last.size > 1 }
                    redundant_elements = duplicate_groups.map { |group| group.last - [group.last.first] }.flatten
                    redundant_elements.each(&:destroy)
                    

                    【讨论】:

                    • 正是我想要的! Rails 迁移完成!干杯
                    【解决方案15】:

                    我必须do this recently on Oracle,但在 MySQL 上的步骤是相同的​​。这是很多数据,至少与我习惯使用的数据相比,所以我的重复数据删除过程是相对重量级的。我将其包括在此处,以防其他人遇到类似问题。

                    我的重复记录有不同的 ID、不同的 updated_at 次、可能不同的 updated_by ID,但所有其他列都相同。我想保留任何重复集的最新更新。

                    我结合使用 Rails 逻辑和 SQL 来完成它。

                    第一步:使用模型逻辑运行 rake 脚本来识别重复记录的 ID。 ID 保存在文本文件中。

                    第二步:创建一个临时表,其中包含一列、要删除的 ID,从文本文件中加载。

                    第三步:创建另一个临时表,其中包含我要删除的所有记录(以防万一!)。

                    CREATE TABLE temp_duplicate_models 
                      AS (SELECT * FROM models 
                      WHERE id IN (SELECT * FROM temp_duplicate_ids));
                    

                    第四步:实际删除。

                    DELETE FROM models WHERE id IN (SELECT * FROM temp_duplicate_ids);
                    

                    【讨论】:

                      【解决方案16】:

                      您可以通过以下方式将不同的记录复制到新表中:

                       select distinct * into NewTable from MyTable
                      

                      【讨论】:

                      • 虽然这不会捕获具有相同但不同的唯一 ID 的记录?
                      • 这就是为什么我在他的评论中告诉他“你需要一个 keyfield(ID) 来查找以使记录与众不同”
                      • 错过了你的评论 :)
                      猜你喜欢
                      • 2018-04-02
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-08-01
                      • 2011-10-09
                      • 1970-01-01
                      • 2018-04-09
                      • 1970-01-01
                      • 2022-01-20
                      相关资源
                      最近更新 更多