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

面试官:MySQL是如何查找和删除重复行的?我什至不能写它,.

时间:2023-04-01 14:52:04 Java

本文介绍了如何在数据库中查找重复行。对于初学者来说,这是一个非常普遍的问题。方法也很简单。这个问题还可以有其他的演化,比如如何找到“有两个字段的重复行”(问题在#mysqlIRC频道问)如何找到重复行第一步是定义什么样的行是重复行。大多数时候很简单:其中一列的值相同。本文使用这个定义,也许你对“repeat”的定义比这个更复杂,你需要对sql做一些改动。本文要用到的数据样本:createtabletest(idintnotprimarykey,daydatenotnull);插入测试(id,天)值(1,'2006-10-08');插入测试(id,天)值(2,'2006-10-08');插入测试(id,天)值(3,'2006-10-09');从测试中选择*;+----+------------+|编号|天|+----+------------+|1|2006-10-08||2|2006-10-08||3|2006-10-09|+----+------------+前两行在day字段中的值相同,那么如何将它们视为重复行,这里是一个查询语句来查找。查询语句使用GROUPBY子句对具有相同字段值的行进行分组,然后计算分组的大小。从测试GROUPBY天中选择天,计数(*);+------------+----------+|天|计数(*)|+-------------+----------+|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(日期不为空,min_idint不为空);插入to_delete(day,min_id)从测试组中选择日期,MIN(id)bydayhavingcount(*)>1;从to_delete选择*;+----------+--------+|天|最小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);插入a_b_c(b,c)值(1,2);插入a_b_c(b,c)值(1,3);插入a_b_c(b,c)值(2,1);插入a_b_c(b,c)值(2,2);插入a_b_c(b,c)值(2,3);插入a_b_c(b,c)值(3,1);插入a_b_c(b,c)值(3,2);插入a_b_c(b,c)值(3,3);现在,您可以很容易地看到表中有一些重复的行,但是您找不到具有相同对{b,c}的两行。这就是问题变得困难的原因。不正确的查询语句如果将两列组合在一起,您将得到不同的结果,这取决于如何分组和计算大小。正是在这里,发问者被困住了。有时查询会找到一些重复的行,但会遗漏其他行。这是他使用的查询selectb,c,count(*)froma_b_cgroupbyb,chavingcount(distinctb>1)orcount(distinctc>1);结果返回所有行,因为CONT(*)总是1。为什么?因为>1写在COUNT()里面。这个错误很容易忽略,实际上相当于selectb,c,count(*)froma_b_cgroupbyb,chavingcount(1)orcount(1);为什么?因为(b>1)是一个布尔值,所以它根本不是你想要的结果。你想要的是selectb,c,count(*)froma_b_cgroupbyb,chavingcount(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_cgroupbybhavingcount(*)>1unionselectcasvalue,count(*)ascnt,'c'aswhat_colfroma_b_cgroupbychavingcount(*)>1;+--------+------+----------+|价值|碳纳米管|什么栏|+--------+-----+----------+|1|3|b||2|3|b||3|3|b||1|3|c||2|3|c||3|3|c|+------+-----+----------+输出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|3||13|3|1||14|3|2||15|3|3|+----+-----+-----+这种方法比使用UNION效率低得多,并且显示每个重复的行,而不是重复的字段值。还有一种方法是将表查询与组的嵌套查询结果进行join。写法比较复杂,但是对于复杂的数据或者对效率要求高的情况是必须的。selecta,a_b_c.b,a_b_c.cfroma_b_cleftouterjoin(selectbfroma_b_cgroupbybhavingcount(*)>1)asbona_b_c.b=b.bleftouterjoin(selectcfroma_b_cgroupbychavingcount(*)>1)ascona_b_c.c=c.cwhereb.bisnotnullorc.cisnotnull上面的作品,我敢肯定还有其他人。如果能用UNION,我觉得会是最简单的。作者:愤怒的韭菜\来源:https://blog.csdn.net/zhengzh...\原文:http://www.xaprb.com/blog/200...近期热门文章推荐:1.1000+Java面试题及答案(2022最新版)2.精彩!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!