按两列查找并删除重复行
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
【讨论】:
以上是关于按两列查找并删除重复行的主要内容,如果未能解决你的问题,请参考以下文章