[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 ...
随机推荐
- 精讲RestTemplate第4篇-POST请求方法使用详解
本文是精讲RestTemplate第4篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...
- LeetCode 120. Triangle (三角形最小路径和)详解
题目详情 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径 ...
- stat 命令家族(3)- 详解 mpstat
性能测试必备的 Linux 命令系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1819490.html 介绍 输出 CPU 相关信息 m ...
- python关于函数调用作为参数的说明&&装饰器
python关于函数调用作为参数的说明&&装饰器 简单的: 先看代码: def out(): print('out') def inner(): return 'inner' retu ...
- Oracle从回收站找回误删的数据
Step1 先根据删除时间查看删除了那些表 select * from recyclebin where type = 'TABLE' and createtime like '${删除时间}%' o ...
- three.js 着色器材质内置变量
这篇郭先生说一下three.js着色器的内置变量,分别是 gl_PointSize:在点渲染模式中,控制方形点区域渲染像素大小(注意这里是像素大小,而不是three.js单位,因此在移动相机是,所看到 ...
- [Kong 与 Konga与postgres数据库] 之 Kuberneres 部署
1.Kong的概述 Kong是一个clould-native.快速的.可扩展的.分布式的微服务抽象层(也称为API网关.API中间件或在某些情况下称为服务网格)框架.Kong作为开源项目在2015年推 ...
- 【NOI2004】郁闷的出纳员 - Splay
题目描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资 ...
- Antd cracoTs Js 配置流程
JS:文档:0.1.4 配置 js 环境.note链接:http://note.youdao.com/noteshare?id=e32fa75c1baa014b5819fa5e22887dbc& ...
- Fisher Coffee 测评(非严格控温控水)
Fisher Coffee 测评(非严格控温控水) 咖啡生产批次:2020-05-29 打分区间:1~5,0.5间隔 批次:2020.6.3 酸为主,苦为主. 无甘,有甘,微甘,较甜,甘甜. 不苦,有 ...