按两列查找并删除重复行

Posted

技术标签:

【中文标题】按两列查找并删除重复行【英文标题】:Find and remove duplicate rows by two columns 【发布时间】:2012-12-29 17:36:30 【问题描述】:

我阅读了所有相关的重复问题/答案,我发现这是最相关的答案:

INSERT IGNORE INTO temp(MAILING_ID,REPORT_ID) 
SELECT DISTINCT MAILING_ID,REPORT_IDFROM table_1
;

问题是我想删除 col1 和 col2 的重复项,但还想将 table_1 的所有其他字段包含到插入中。

我尝试以这种方式添加所有相关列:

INSERT IGNORE INTO temp(M_ID,MAILING_ID,REPORT_ID,
MAILING_NAME,VISIBILITY,EXPORTED) SELECT DISTINCT  
M_ID,MAILING_ID,REPORT_ID,MAILING_NAME,VISIBILITY,
EXPORTED FROM table_1
;


M_ID(int,primary),MAILING_ID(int),REPORT_ID(int),
MAILING_NAME(varchar),VISIBILITY(varchar),EXPORTED(int)

但它会将所有行插入到 temp 中(包括重复行)

【问题讨论】:

好吧,一方面——不要在你的情况下使用INSERT IGNORE,第二个——>你的数据库表是如何设置的? 你能提供样本记录吗? @Neal 用实际的字段名称和类型更新了我的问题 【参考方案1】:

您首先需要通过使用having子句对两个字段进行分组来查找重复项。

    Select identField1, identField2, count(*) FROM yourTable
        GROUP BY identField1, identField2
          HAVING count(*) >1

如果这返回了你想要的,那么你可以将它用作子查询和

  DELETE FROM yourTable WHERE field in (Select identField1, identField2, count(*) FROM yourTable
        GROUP BY identField1, identField2
          HAVING count(*) >1 )

【讨论】:

这会保留其中一个重复行吗? (我想保留一个,而不是删除任何有重复的行) 它将删除所有重复项。如果你想保留一个,你可以选择一个你不聚合的字段的最大值或最小值。一个快速的谷歌出现了***.com/questions/3777633/…,它还链接到其他相同的问题。 如果表只有 2 列并且两列都被分组了,如何防止删除所有重复项?【参考方案2】:

删除多列重复行最好的方法是最简单的:

添加唯一索引:

ALTER IGNORE TABLE your_table ADD UNIQUE (field1,field2,field3);

上面的 IGNORE 确保只保留第一个找到的行,其余的被丢弃。

(如果您需要将来重复和/或知道它们不会再次发生,则可以删除该索引)。

【讨论】:

比相关子查询容易得多。 mysql 5.7.4 开始,ALTER TABLE 的 IGNORE 子句被删除,使用它会产生错误。 在 mysql 5.5 中可能存在一个错误。使用 set old_alter_table=1 参见文档:dev.mysql.com/doc/refman/5.5/en/alter-table.html 由于与快速索引创建相关的错误(错误 #40344),ALTER IGNORE TABLE ... ADD UNIQUE INDEX 不会删除重复的行。 IGNORE 关键字被忽略。如果存在任何重复行,则操作将失败并出现 Duplicate entry 错误。一种解决方法是在运行 ALTER IGNORE TABLE ... ADD UNIQUE INDEX 语句之前设置 old_alter_table=1。 如果我想先修改一列,这将如何工作。例如,这不起作用:ALTER IGNORE TABLE mytable ADD UNIQUE (FROM_UNIXTIME(CEIL(UNIX_TIMESTAMP(timestamp) / 5) * 5), id2) ALTER IGNORE 已被弃用【参考方案3】:

注意:此解决方案是另一种老式的解决方案。


如果你不能达到你想要的,那么你可以试试我的“oldschool”方法:

首先,运行此查询以获取重复记录:

select   column1,
         column2,
         count(*)
from     table
group by column1,
         column2
having   count(*) > 1
order by count(*) desc

之后,选择这些结果并将它们粘贴到记事本++中:

现在使用notepad++的查找和替换特性替换它们;首先“删除”然后“插入”这样的查询(从现在开始,出于安全原因,我的值将是 AAAA)。

特别注意:由于正则表达式匹配每行末尾的 '\r\n',请在 notepad++ 中的最后一行数据的末尾创建另一个新行:

查找什么正则表达式:\D*(\d+)\D*(\d+)\D*\r\n

替换为字符串:delete from table where column1 = $1 and column2 = $2; insert into table set column1 = $1, column2 = $2;\r\n

现在,最后,将这些查询粘贴到 MySQL Workbench 的查询控制台并执行。您只会看到每条重复记录出现一次。

此答案适用于仅由两列没有 ID 的关系表。我认为您可以将其应用于您的情况。

【讨论】:

【参考方案4】:

您始终可以通过将这两个唯一字段分组来获取主 ID

select count(*), id as count from table group by col a, col b having count(*)>1;

然后

delete from table where id in ( select count(*), id as count from table group by col a, col b having count(*)>1) limit maxlimit;

您也可以使用max() 代替limit

【讨论】:

limit maxlimit 有什么作用? @Notflip 表示要删除多少重复行 嵌套查询和删除查询不能使用同一张表。 这不起作用@SudhanshuJain,你测试过吗??【参考方案5】:

对于 Mysql:

DELETE t1 FROM yourtable t1 
  INNER JOIN yourtable t2 WHERE t1.id < t2.id 
    AND t1.identField1 = t2.identField1 
    AND t1.identField2 = t2.identField2;

【讨论】:

【参考方案6】:

这适用于任何版本的 MySQL,包括 5.7+。它还通过使用双嵌套子查询来处理错误You can't specify target table 'my_table' for update in FROM clause。它只删除一个重复行(后一个),因此如果您有 3 个或更多重复行,则可以多次运行查询。它从不删除唯一的行。

DELETE FROM my_table
WHERE id IN (
  SELECT calc_id FROM (
    SELECT MAX(id) AS calc_id
    FROM my_table
    GROUP BY identField1, identField2
    HAVING COUNT(id) > 1
  ) temp
)

我需要这个查询,因为我想在两列上添加一个 UNIQUE 索引,但我需要先丢弃一些重复的行。

【讨论】:

You can't specify target table 'table' for update in FROM clause 由于WHERE 子句使用双重嵌套,它可以工作。这就是诱使 MySQL 引擎在不产生冲突的情况下允许此查询的魔力。【参考方案7】:

如果您在 select 子句中选择多个列,则在大型数据集中,例如: select x,y,z from table1。 并且要求是根据两列删除重复项:从上面的示例中让 y,z 那么你可以使用下面而不是使用“group by”和“sub query”的组合,这在性能上很糟糕:

select x,y,z 
from (
select x,y,z , row_number() over (partition by y,z) as index_num
from table1) main
where main.index_num=1

【讨论】:

以上是关于按两列查找并删除重复行的主要内容,如果未能解决你的问题,请参考以下文章

如何根据两列删除所有重复行?

R - 根据两列识别和删除重复行

如何根据一列是不是具有特定值来查找重复行并删除输出?

awk 根据两列和自定义重复规则删除重复项

按两列对数据框进行排序(有条件)[重复]

MySQL - 在一个查询中按两列计数[重复]