[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 ...
随机推荐
- AlgorithmMan,一套免费的算法演示神器
概述 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/971 访问. 文章末尾附带GitHub开源下载地址. 0.概述 ...
- Quartz.Net的基础使用方法,多任务执行继续扩展
前一篇随笔讲了Quartz多任务的简单实现 Quartz.Net的基础使用方法,多任务执行 这一篇,来简单对前一篇进行一下简单的扩展 看了前一篇的代码会发现,每次新增一个任务还要去GetJobs方法里 ...
- .Net微服务实战之Kubernetes的搭建与使用
系列文章 .Net微服务实战之技术选型篇 .Net微服务实战之技术架构分层篇 .Net微服务实战之DevOps篇 .Net微服务实战之负载均衡(上) .Net微服务实战之CI/CD 前言 说到微服务就 ...
- 关于java中jdk的环境变量配置
关于java中jdk的环境变量配置 烦死人,在网上找了很长时间.最终找到了一个方法!现在将其总结帮助后来人. 方法/步骤 1 下载好jdk,并按照提示一步步安装,最后记下jdk所在的安装位置,这里 ...
- C、C++、Java、Python该怎么选
对于很多对编程感兴趣的小伙.或是正在读计算机专业的大学生来说,不知道要选择哪一门编程语言发展.对于计算机专业的学生,一般的学习都普遍会开始设C.C++.Java等热门的编程语言,但还是不太清楚选择哪一 ...
- eric4 中 pyqt .py文件结尾的 代码
if __name__ == "__main__": import sys app = QtGui.QApplication(sys.argv) ui = MainWindow() ...
- .net Core 下使用 X509Certificate2 给报文加签
起因 项目开发中途出现需求需要对接其他公司接口,使用证书进行认证传输,之前在.Net下搞过但是都是对方给我证书 这次需要我生成公钥/私钥,公钥给他这样操作. 生成私钥/公钥(这里是RSA算法,长度规定 ...
- IDEA的externel tool配置Javap -c 命令
1.ctrl+alt+s打开设置界面,找到Tool-> External Tools 点击 +来增加一个新的外部工具. 在tool setting 的Program输入工具的路径,可以插入宏,比 ...
- 操作系统-文件系统(5)Linux文件系统管理
主流分区机制有MBR和GPT两种 MBR分区:第一个扇区最重要,里面有:引导代码(Bootstrap code area)及分区表(partition table), 其中Bootstrap code ...
- 牛客网PAT练兵场-在霍格沃茨找零钱
题目地址:https://www.nowcoder.com/pat/6/problem/4063 题意:按照题目的进制计算即可 /** * *作者:Ycute *时间:2019-11-14-21.45 ...