[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 ...
随机推荐
- Cross-Stage-Partial-Connections
- [leetcode/lintcode 题解] 有效回文 II · Valid Palindrome II
[题目描述] 给一个非空字符串 s,你最多可以删除一个字符.判断是否可以把它变成回文串. 在线评测地址: https://www.lintcode.com/problem/valid-palindro ...
- C# 使用代理实现线程间调用
实现功能: 后台线程改变窗体控件(flowLayoutPanel1)的状态. 利用 this.flowLayoutPanel1.InvokeRequired == false,可以知道是主线程调用的自 ...
- LeetCode198 House Robber(打家劫舍)
题目 You are a professional robber planning to rob houses along a street. Each house has a certain amo ...
- Newbe.Claptrap 框架如何实现 Claptrap 的多样性?
Newbe.Claptrap 框架如何实现 Claptrap 的多样性?最近整理了一下项目的术语表.今天就谈谈什么是 Claptrap Design 和 Claptrap Factory. 特别感谢 ...
- three.js 着色器材质内置变量
这篇郭先生说一下three.js着色器的内置变量,分别是 gl_PointSize:在点渲染模式中,控制方形点区域渲染像素大小(注意这里是像素大小,而不是three.js单位,因此在移动相机是,所看到 ...
- 【AI 算法评测】BERT 对 NLP 效果的改善,不负众望!
AI 在各大领域的发展有目共睹,而作为人工智能皇冠上的明珠--自然语言处理却成果了了,大多实现或者以半成品的形式躺在实验室中,或者仅仅作为某个产品的辅助功能.而这一情况在 BERT 出现后出现了很大的 ...
- wsl 2 unbuntu 部署 asp.net core 使用 nginx 做反向代理,调试文件上传失败
继上一篇 asp.net core 3.1多种身份验证方案,cookie和jwt混合认证授权 的公司内部项目上线后发现文件上传功能有问题. 上传的文件超过50M以后前端就报错了,没有状态返回,也没有响 ...
- 服务器基本配置(ubuntu)
服务器基本配置(ubuntu) 学习目标: 修改初始服务器名字(ubuntu 16.04 ) 修改初始服务器名字(ubuntu 18.04 ) ubuntu换源 更改默认python版本 安装软件出现 ...
- Python1--简介及基础语法
0. 简介 Python易于学习的编程语言,有很多现成的第三方库可以调用,不用重复造轮子,老话说:"人生苦短,我用 Python" 1. 安装Python Mac:brew ins ...