当前位置: 首页 > 后端技术 > Java

MySQL如何查找和删除重复行?

时间:2023-04-01 17:18:36 Java

如何查找重复行如何删除重复行如何查找多列重复行错误查询几种正确方法如何查找重复行第一步定义什么样的行是重复行。大多数时候很简单:其中一列的值相同。本文使用这个定义,也许你对“repeat”的定义比这个更复杂,你需要对sql做一些改动。本文要用到的数据示例:createtabletest(idintnotnullprimarykey,daydatenotnull);insertintotest(id,day)values(1,'2006-10-08');insertintotest(id,day)values(2,'2006-10-08');insertintotest(id,day)values(3,'2006-10-09');select*fromtest;+----+-------------+|编号|天|+----+------------+|1|2006-10-08||2|2006-10-08||3|2006-10-09|+----+------------+前两行在日期字段中具有相同的值,那么我如何将它们视为重复行好的,这里是要查找的查询语句。查询语句使用GROUPBY子句对具有相同字段值的行进行分组,然后计算分组的大小。selectday,count(*)fromtestGROUPBYday;+------------+----------+|天|计数(*)|+-------------+---------+|2006-10-08|2||2006-10-09|1|+------------+----------+组大小大于1的重复行。如果只想显示重复行,必须使用HAVING子句,如selectday,count(*)fromtestgroupbydayHAVINGcount(*)>1;+-------------+--------+|天|计数(*)|+------------+---------+|2006-10-08|2|+------------+------------+这是基本技巧:按具有相同值的字段分组,然后显示大小大于1的组。为什么不能使用WHERE子句?因为WHERE子句过滤分组前的行,所以HAVING子句过滤分组后的行。如何删除重复行一个相关的问题是如何删除重复行。一个常见的任务是只保留一行重复行并删除其他行,然后您可以创建适当的索引以防止将来将重复行写入数据库。同样,第一件事是弄清楚什么是重复行。你想保留哪条线?第一行,还是某个字段具有最大值的行?在本文中,假设您要保留第一行——id字段值最小的行,这意味着您要删除其他行。也许最简单的方法是通过临时表。特别是对于MYSQL,有些限制是不能在一个查询语句中同时选择和更新一个表。为了简单起见,这里只使用了临时表的方法。我们的任务是:删除除分组中id字段值最小的行之外的所有重复行。因此,您需要找出大小大于1的组,以及您要保留的行。您可以使用MIN()函数。这里的语句是创建一个临时表,用DELETE找到需要删除的行。创建临时表to_delete(daydatenotnull,min_idintnotnull);插入to_delete(day,min_id)selectday,MIN(id)fromtestgroupbydayhavingcount(*)>1;select*fromto_delete;+----------+--------+|天|min_id|+------------+--------+|2006-10-08|1|+------------+----------+有了这些数据,你就可以开始删除“脏数据”行了。方法有好几种,各有优缺点(详见我的文章SQL中的多对一问题),这里不做详细比较,只说明关系型数据库中支持的标准方法查询子句。deletefromtestwhereexists(select*fromto_deletewhereto_delete.day=test.dayandto_delete.min_id<>test.id)如何在多列上查找重复行b和c两个字段分别与b和c关联其他两个表的字段。我想找到在字段b或字段c上具有重复值的行。乍一看很难理解,交谈后明白了:他要分别为b和c创建唯一索引。如上所述,查找某个字段上有重复值的行就像按组分组并计算组的大小一样简单。而且查找有重复字段的行也很简单,只需要将所有字段放在group子句中即可。但是如果是判断是b字段重复还是c字段重复,问题就难多了。这里提问者使用的样本数据createtablea_b_c(aintnotnullprimarykeyauto_increment,bint,cint);插入a_b_c(b,c)值(1,1);insertintoa_b_c(b,c)值为(1,2);insertintoa_b_c(b,c)值为(1,3);insertintoa_b_c(b,c)值为(2,1);insertintoa_b_c(b,c)值(2,2);insertintoa_b_c(b,c)值(2,3);insertintoa_b_c(b,c)值(3,1));insertintoa_b_c(b,c)值(3,2);insertintoa_b_c(b,c)值(3,3);现在,您可以很容易地看到表中有一些重复的行,但是您找不到具有相同对{b,c}的两行。这就是问题变得困难的原因。不正确的查询语句如果将两列组合在一起,您将得到不同的结果,这取决于如何分组和计算大小。正是在这里,发问者被困住了。有时查询会找到一些重复的行,但会遗漏其他行。这是他使用的查询selectb,c,count(*)froma_b_cgroupbyb,havingcount(distinctb>1)orcount(distinctc>1);结果返回所有行,因为CONT(*)始终为1。为什么?因为>1写在COUNT()里面。这个错误很容易忽略,实际上等价于selectb,c,count(*)froma_b_cgroupbyb,havingcount(1)orcount(1);为什么?因为(b>1)是一个布尔值,所以它根本不是你想要的结果。你想要的是selectb,c,count(*)froma_b_cgroupbyb,havingcount(distinctb)>1orcount(distinctc)>1;返回空结果。显然,因为没有重复的{b,c}。这个人尝试了很多其他的OR和AND的组合,一个字段用于分组,另一个字段用于计算大小,像这样selectb,count(*)froma_b_cgroupbybhavingcount(distinctc)>1;+------+------------+|乙|计数(*)|+------+----------+|1|3||2|3||3|3|+------+----------+他们都找不到所有重复的行。最令人沮丧的是,对于某些情况,如果你错误地认为这是这样写的话,这个陈述是有效的,但对于其他情况,你可能会得到错误的结果。事实上,简单地使用GROUPBY是行不通的。为什么?因为当你对某个字段使用groupby时,你会把另一个字段的值分散到不同的组中。对这些字段进行排序可以看到这些效果,就像分组一样。首先,对b字段进行排序,看看它是如何分组的。当你对b字段进行排序(分组)时,c的相同值被分成不同的组,所以你不能使用COUNT(DISTINCTc)来计算大小。COUNT()等内部函数只作用于同一组,对不同组的行无能为力。同样,如果对c字段进行排序,同样值的b也会被分到不同的组中,无论如何也达不到我们的目的。几种正确的方法或许最简单的方法就是找到某个字段重复的行,然后用UNION把它们拼在一起,像这样:selectbasvalue,count(*)ascnt,'b'aswhat_colfroma_b_cgroupbyb有count(*)>1unionselectc作为值,count(*)作为cnt,'c'作为what_colfroma_b_cgroupbychavingcount(*)>1;+-------+-----+----------+|价值|碳纳米管|what_col|+--------+-----+---------+|1|3|b||2|3|b||3|3|b||1|3|c||2|3|c||--c+3|------3|-+----------+输出what_col字段,以提示重复了哪个字段。另一种方法是使用嵌套查询:selecta,b,cfroma_b_cwherebin(selectbfroma_b_cgroupbybhavingcount(*)>1)orcin(selectcfroma_b_cgroupbychavingcount(*)>1);+----+-----+-----+|一个|乙|c|+----+------+-----7|1|1||8|1|2||9|1|3||10|2|1||11|2|2||12|2|1|3||13||14|3|2||15|3|3|+----+-----+------+这种方法比使用UNION效率低很多,而且显示的是每一个重复的行,而不是一个重复的字段值。还有一种方法是将表查询与组的嵌套查询结果进行join。写法比较复杂,但是对于复杂的数据或者对效率要求高的情况是必须的。选择a,A_B_C.B,a_B_C.CFROMA_B_CLeftOutrin(SelectBFROMA_B_CGROUPBYBHAVINGCOUNT(*)>1)asbonA_B_C.B=B.BLEFTOUTERJOIN(SelectCFROMA_B_CGROUPBYCROUPBYCHAVingcount(*)>1)ascona_b_c.c=c.cwhereb.bisnotnullorc.cisnotnull上面的作品,我敢肯定还有其他人。如果能用UNION,我觉得会是最简单的。