[Oracle/SQL]找出id为0的科目考试成绩及格的学生名单的四种等效SQL语句
本文是受网文 《一次非常有意思的SQL优化经历:从30248.271s到0.001s》启发而产生的。
网文没讲创建表的数据过程,我帮他给出。
创建科目表及数据:
CREATE TABLE tb_course ( id NUMBER not null primary key, name NVARCHAR2(10) not null ) Insert into tb_course select rownum,dbms_random.string('*',dbms_random.value(6,10)) from dual connect by level<=100 order by dbms_random.random
创建学生表及数据:
CREATE TABLE tb_student ( id NUMBER not null primary key, name NVARCHAR2(20) not null ) Insert into tb_student select rownum,dbms_random.string('*',dbms_random.value(15,20)) from dual connect by level<=70000 order by dbms_random.random
创建成绩表及数据:
CREATE TABLE tb_score ( id NUMBER not null primary key, studentid int not null, courseid int not null, score int not null ) Insert into tb_score select rownum,dbms_random.value(0,70000),dbms_random.value(0,100),dbms_random.value(0,100) from dual connect by level<=700000 order by dbms_random.random
而要取的考id=0的科目及格的学生列表,可以用下面两种等效半连接SQL语句:
select * from tb_student stu where stu.id in(select studentid from tb_score where courseid=0 and score>60) select * from tb_student stu where exists(select studentid from tb_score where courseid=0 and score>60 and tb_score.studentid=stu.id)
如果是要走内连接的方式,则要把tb_score表的studentid清除一次重复,如果不清重复,那么两表连接如果有一对多的情况就会产生多条数据。上面的半连接只要存在就算条件通过,存在一条和存在多条等效,自然就不用清除重复了。
select stu.* from (select distinct studentid from tb_score where courseid=0 and score>60) score, tb_student stu where score.studentid=stu.id select stu.* from tb_student stu, (select distinct studentid from tb_score where courseid=0 and score>60) score where score.studentid=stu.id
要找出重复元素可以采用下面sql:
SQL> select studentid,count(studentid) from 2 (select studentid from tb_score where courseid=0 and score>60) score 3 group by studentid 4 having count(studentid)>1; STUDENTID COUNT(STUDENTID) ---------- ---------------- 9508 2 55358 2 10852 2 55731 2 5751 2 503 2 已选择6行。 已用时间: 00: 00: 00.01
但这样还是不直观,于是可以查查重复记录究竟是怎么产生的:
SQL> select * from tb_score where studentid in (select studentid from 2 (select studentid from tb_score where courseid=0 and score>60) score 3 group by studentid 4 having count(studentid)>1) 5 and courseid=0 6 order by 2,3,4; ID STUDENTID COURSEID SCORE ---------- ---------- ---------- ---------- 173720 503 0 92 64695 503 0 94 157901 5751 0 71 475290 5751 0 93 144229 9508 0 67 142179 9508 0 89 240689 10852 0 73 625426 10852 0 75 203725 55358 0 86 431998 55358 0 100 83002 55731 0 68 356457 55731 0 83 已选择12行。 已用时间: 00: 00: 00.03
这下看清楚,原来有些人考了两次! 这可以对应现实中考两次取最高分或是正考一次补考一次的例子。
因为上面四条SQL语句运行都挺快,我都没加索引都是如此,于是就先不用优化了,以后再说。
2020年1月21日
附:上面我用到的全部SQL语句:
CREATE TABLE tb_course ( id NUMBER not null primary key, name NVARCHAR2(10) not null ) Insert into tb_course select rownum,dbms_random.string('*',dbms_random.value(6,10)) from dual connect by level<=100 order by dbms_random.random CREATE TABLE tb_student ( id NUMBER not null primary key, name NVARCHAR2(20) not null ) Insert into tb_student select rownum,dbms_random.string('*',dbms_random.value(15,20)) from dual connect by level<=70000 order by dbms_random.random CREATE TABLE tb_score ( id NUMBER not null primary key, studentid int not null, courseid int not null, score int not null ) Insert into tb_score select rownum,dbms_random.value(0,70000),dbms_random.value(0,100),dbms_random.value(0,100) from dual connect by level<=700000 order by dbms_random.random select * from tb_student stu where stu.id in(select studentid from tb_score where courseid=0 and score>60) select * from tb_student stu where exists(select studentid from tb_score where courseid=0 and score>60 and tb_score.studentid=stu.id) select stu.* from (select distinct studentid from tb_score where courseid=0 and score>60) score, tb_student stu where score.studentid=stu.id select stu.* from tb_student stu, (select distinct studentid from tb_score where courseid=0 and score>60) score where score.studentid=stu.id select studentid,count(studentid) from (select studentid from tb_score where courseid=0 and score>60) score group by studentid having count(studentid)>1 select * from tb_score where studentid in (select studentid from (select studentid from tb_score where courseid=0 and score>60) score group by studentid having count(studentid)>1) and courseid=0 order by 2,3,4
2020-01-22
分类:
Oracle.权衡比较Sql文
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2017-01-21 为什么一个目录里放超过十个Mp4文件会导致资源管理器和播放程序变卡变慢?
2015-01-21 【高中数学/函数/幂函数】若a=(1/2)^2/3,b=(1/5)^2/3,c=(1/2)^1/3,则a,b,c的大小关系是?
2015-01-21 【Canvas与艺术】蓝色渐变单脚四钉正方形中写盈字
2014-01-21 【Canvas与艺术】双齿轮啮合传动