[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]找出id为0的科目考试成绩及格的学生名单的四种等效SQL语句的更多相关文章
- 转 A 、B两张表,找出ID字段中,存在A表,但是不存在B表的数据
A.B两张表,找出ID字段中,存在A表,但是不存在B表的数据,A表总共13W数据,去重后大约3万条数据,B表有2W条数据,且B表的ID有索引. 方法一 使用not in,容易理解,效率低. selec ...
- 用SQL找出前N名
业务系统中常常会有排名的需求,考试和比赛中则更普遍了.Excel 中也有个 Rank 函数供排名之用,数据库中更不例外了. 如果须要找出工资最高的前三个员工工资(及其员工号). 只是."前三 ...
- oracle数据库【表复制】insert into select from跟create table as select * from 两种表复制语句区别
create table as select * from和insert into select from两种表复制语句区别 create table targer_table as select ...
- SQL 四种基本数据操作语句的基本使用
SQL中含有四种基本的数据操作语句,分别是增(INSERT),删(DELETE),查(SELECT),改(UPDATE).下面简单介绍这四种语句的用法. 1:增(INSERT) 可分为两种查询情况,一 ...
- Java/sql找出oracle数据库有空格的列
1.java方式 String table_sql = "select table_name from user_tables";//所有用户表 List<String> ...
- Oracle PL/SQL 找出100以内是3和5的倍数的数 循环语句
循环: loop --执行代码 exit when 表达式;--当表达式为真退出循环.(注意,其编写位置决定循环为先判断还是先执行,相当于java的while或do-while) end loop; ...
- oracle中找出某个字段中有非数字型的记录
工作中遇到一个大表记录中有非法非数字字符,不想用正则语法去做, 用一条SQL语句查出来的方法如下: select * from table where translate(col,'*01234567 ...
- sql 找出不包含字母、不包含汉字的数据
--1.不包含字母 SELECT * FROM t WHERE str NOT LIKE '%[a-zA-Z]%' SELECT * FROM t --2.不包含汉字 SELECT * FROM t ...
- Oracle中找出用户的上次登录时间
可以使用如下sql语句: select t1.username,t1.logon_time last_logon_time,t2.account_status,created 账号创建时间 from ...
随机推荐
- webgl实现发光线框(glow wireframe)效果
在之前这篇文章, WebGL 单通道wireframe渲染 我们介绍了webgl如何实现单通道wireframe的效果. 本篇文章就是在此技术原理基础之上,来实现发光的wireframe效果. 要实现 ...
- java final关键字与static关键字
一 final关键字 1.final修饰类不可以被继承,但是可以继承其他类. 例如: class Yy {} final class Fu extends Yy{} //可以继承Yy类 class ...
- C#LeetCode刷题之#541-反转字符串 II(Reverse String II)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3951 访问. 给定一个字符串和一个整数 k,你需要对从字符串开头 ...
- Vue Element-UI 中列表单选的实现
el-table中单选的实现 引用场景: 选择单条数据进行业务操作 实现方式: 给el-table-column设置el-radio Template 代码 <div class="r ...
- jquary常见问题总结
如何调用本地json 1. 调用 <script src="solution.json?cb=readData"></script> 2. json 修改 ...
- [开源] .Net ORM FreeSql 1.8.0-preview 最新动态播报(番号:我还活着)
写在开头 FreeSql 是 .NET 开源生态下的 ORM 轮子,在一些人眼里属于重复造轮子:不看也罢.就像昨天有位朋友截图某培训直播发给我看,内容为:"FreeSQL(个人产品),自己玩 ...
- IOS 如何持久化自定义对象 2014-08-01 01:38
如果持久话自定义对象 那么这个对象一定要遵循 NSCoding 协议 并实现编解码:然后再将编解码后的数据 NSKeyedArchiver 到NSData中 @interface NSKeyAnd ...
- Jmeter 常用函数(12)- 详解 __machineName
如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.html 作用 返回机器(电脑)名称 语法格式 ${_ ...
- openstack-neutron-OVS agent分析
参考链接: https://blog.csdn.net/sld880311/article/details/77978369 https://github.com/jffree/neutron-cod ...
- 玩转Spring——Spring整合JDBC
传统JDBC代码的弊端在传统的jdbc代码中,即使是执行一条简单的SQL语句,其实现的整个流程也是极为繁琐的,先打开数据库连接执行sql,然后组装结果,最后关闭数据库资源,这中间还有大量的try... ...