最近在做题库系统,由于在题库中添加了重复的试题,所以需要查询出重复的试题,并且删除掉重复的试题只保留其中1条,以保证考试的时候抽不到重复的题。
首先写了一个小的例子:
一、单个字段的操作
这是数据库中的表:
分组介绍
Select 重复字段 From 表 Group By 重复字段 Having Count(*)>1
查看是否有重复的数据:
GROUP BY <列名序列>
HAVING <组条件表达式>
查询出&#xff1a;根据dname分组&#xff0c;同时满足having字句中组条件表达式&#xff08;重复次数大于1&#xff09;的那些组
count(*)与count(1) 其实没有什么差别&#xff0c;用哪个都可以
count(*)与count&#xff08;列名&#xff09;的区别&#xff1a;
count(*)将返回表格中所有存在的行的总数包括值为null的行&#xff0c;然而count(列名)将返回表格中除去null以外的所有行的总数(有默认值的列也会被计入&#xff09;
1、 查询全部重复的数据
Select * From 表 Where 重复字段 In (Select 重复字段 From 表 Group By 重复字段 Having Count(*)>1)
2、删除全部重复试题
将上面的查询select改为delete&#xff08;这样会出错的&#xff09;。面试宝典&#xff1a;www.yoodb.com
DELETE
FROMdept
WHEREdname IN (SELECTdnameFROMdeptGROUP BYdnameHAVINGcount(1) > 1)
会出现如下错误&#xff1a;[Err] 1093 - You can&#39;t specify target table &#39;dept&#39; for update in FROM clause
原因是&#xff1a;更新这个表的同时又查询了这个表&#xff0c;查询这个表的同时又去更新了这个表&#xff0c;可以理解为死锁。mysql不支持这种更新查询同一张表的操作
解决办法&#xff1a;把要更新的几列数据查询出来做为一个第三方表&#xff0c;然后筛选更新。
3、查询表中多余重复试题&#xff08;根据depno来判断&#xff0c;除了rowid最小的一个&#xff09;
a. 第一种方法&#xff1a;
SELECT*
FROMdept
WHEREdname IN (SELECTdnameFROMdeptGROUP BYdnameHAVINGCOUNT(1) > 1)
AND deptno NOT IN (SELECTMIN(deptno)FROMdeptGROUP BYdnameHAVINGCOUNT(1) > 1
)
上面这种写法正确&#xff0c;但是查询的速度太慢&#xff0c;可以试一下下面这种方法&#xff1a;
b. 第二种方法&#xff1a;
☆根据dname分组&#xff0c;查找出deptno最小的。然后再查找deptno不包含刚才查出来的。这样就查询出了所有的重复数据&#xff08;除了deptno最小的那行&#xff09;。
SELECT *
FROMdept
WHEREdeptno NOT IN (SELECTdt.minnoFROM(SELECTMIN(deptno) AS minnoFROMdeptGROUP BYdname) dt)
c. 补充第三种方法&#xff1a;
SELECT*
FROMtable_name AS ta
WHEREta.唯一键 <> ( SELECT max( tb.唯一键 ) FROM table_name AS tb WHERE ta.判断重复的列 &#61; tb.判断重复的列 );
4、删除表中多余重复试题并且只留1条
a. 第一种方法&#xff1a;
DELETE
FROMdept
WHEREdname IN (SELECTt.dnameFROM(SELECTdnameFROMdeptGROUP BYdnameHAVINGcount(1) > 1) t)
AND deptno NOT IN (
SELECTdt.mindeptno
FROM(SELECTmin(deptno) AS mindeptnoFROMdeptGROUP BYdnameHAVINGcount(1) > 1) dt
)
b. ☆第二种方法&#xff08;与上面查询的第二种方法对应&#xff0c;只是将select改为delete&#xff09;&#xff1a;
DELETE
FROMdept
WHEREdeptno NOT IN (SELECTdt.minnoFROM(SELECTMIN(deptno) AS minnoFROMdeptGROUP BYdname) dt)
c. 补充第三种方法&#xff08;评论区推荐的一种方法&#xff09;&#xff1a;
DELETE
FROMtable_name AS ta
WHEREta.唯一键 <> (
SELECTt.maxid
FROM( SELECT max( tb.唯一键 ) AS maxid FROM table_name AS tb WHERE ta.判断重复的列 &#61; tb.判断重复的列 ) t );
二、多个字段的操作
单个字段的如果会了&#xff0c;多个字段也非常简单。就是将group by 的字段增加为你想要的即可。
此处只写一个&#xff0c;其他方法请仿照一个字段的写即可。
DELETE
FROMdept
WHERE(dname, db_source) IN (SELECTt.dname,t.db_sourceFROM(SELECTdname,db_sourceFROMdeptGROUP BYdname,db_sourceHAVINGcount(1) > 1) t)
AND deptno NOT IN (SELECTdt.mindeptnoFROM(SELECTmin(deptno) AS mindeptnoFROMdeptGROUP BYdname,db_sourceHAVINGcount(1) > 1) dt
)
总结
其实上面的方法还有很多需要优化的地方&#xff0c;如果数据量太大的话&#xff0c;执行起来很慢&#xff0c;可以考虑加优化一下&#xff1a;
在经常查询的字段上加上索引
将*改为你需要查询出来的字段&#xff0c;不要全部查询出来
小表驱动大表用IN&#xff0c;大表驱动小表用EXISTS。IN适合的情况是外表数据量小的情况&#xff0c;而不是外表数据大的情况&#xff0c;因为IN会遍历外表的全部数据&#xff0c;假设a表100条&#xff0c;b表10000条那么遍历次数就是100*10000次&#xff0c;而exists则是执行100次去判断a表中的数据是否在b表中存在&#xff0c;它只执行了a.length次数。至于哪一个效率高是要看情况的&#xff0c;因为in是在内存中比较的&#xff0c;而exists则是进行数据库查询操作的
作者&#xff1a;千g
blog.csdn.net/n950814abc/article/details/82284838
公众号“Java精选”所发表内容注明来源的&#xff0c;版权归原出处所有&#xff08;无法查证版权的或者未注明出处的均来自网络&#xff0c;系转载&#xff0c;转载的目的在于传递更多信息&#xff0c;版权属于原作者。如有侵权&#xff0c;请联系&#xff0c;笔者会第一时间删除处理&#xff01;
最近有很多人问&#xff0c;有没有读者交流群&#xff01;加入方式很简单&#xff0c;公众号Java精选&#xff0c;回复“加群”&#xff0c;即可入群&#xff01;Java精选面试题&#xff08;微信小程序&#xff09;&#xff1a;3000&#43;道面试题&#xff0c;包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计等&#xff0c;在线随时刷题&#xff01;
------ 特别推荐 ------
特别推荐&#xff1a;专注分享最前沿的技术与资讯&#xff0c;为弯道超车做好准备及各种开源项目与高效率软件的公众号&#xff0c;「大咖笔记」&#xff0c;专注挖掘好东西&#xff0c;非常值得大家关注。点击下方公众号卡片关注。点击“阅读原文”&#xff0c;了解更多精彩内容&#xff01;文章有帮助的话&#xff0c;点在看&#xff0c;转发吧&#xff01;