本文是受网文 《一次非常有意思的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语句的更多相关文章

  1. 转 A 、B两张表,找出ID字段中,存在A表,但是不存在B表的数据

    A.B两张表,找出ID字段中,存在A表,但是不存在B表的数据,A表总共13W数据,去重后大约3万条数据,B表有2W条数据,且B表的ID有索引. 方法一 使用not in,容易理解,效率低. selec ...

  2. 用SQL找出前N名

    业务系统中常常会有排名的需求,考试和比赛中则更普遍了.Excel 中也有个 Rank 函数供排名之用,数据库中更不例外了. 如果须要找出工资最高的前三个员工工资(及其员工号). 只是."前三 ...

  3. 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 ...

  4. SQL 四种基本数据操作语句的基本使用

    SQL中含有四种基本的数据操作语句,分别是增(INSERT),删(DELETE),查(SELECT),改(UPDATE).下面简单介绍这四种语句的用法. 1:增(INSERT) 可分为两种查询情况,一 ...

  5. Java/sql找出oracle数据库有空格的列

    1.java方式 String table_sql = "select table_name from user_tables";//所有用户表 List<String> ...

  6. Oracle PL/SQL 找出100以内是3和5的倍数的数 循环语句

    循环: loop --执行代码 exit when 表达式;--当表达式为真退出循环.(注意,其编写位置决定循环为先判断还是先执行,相当于java的while或do-while) end loop; ...

  7. oracle中找出某个字段中有非数字型的记录

    工作中遇到一个大表记录中有非法非数字字符,不想用正则语法去做, 用一条SQL语句查出来的方法如下: select * from table where translate(col,'*01234567 ...

  8. sql 找出不包含字母、不包含汉字的数据

    --1.不包含字母 SELECT * FROM t WHERE str NOT LIKE '%[a-zA-Z]%' SELECT * FROM t --2.不包含汉字 SELECT * FROM t ...

  9. Oracle中找出用户的上次登录时间

    可以使用如下sql语句: select t1.username,t1.logon_time last_logon_time,t2.account_status,created 账号创建时间 from ...

随机推荐

  1. java_Object类、日期时间类、System类、包装类

    Object类 java.lang.Object 类是所有类的父类.它描述的所有方法子类都可以使用.在对象实例化的时候,最终找的父类就是Object. 如果一个类没有特别指定父类, 那么默认则继承自O ...

  2. Solon 最简单demo---Hello World

    Solon 的项目地址: https://gitee.com/noear/solon 里面杂七杂八的东西很多...今天的目标是整一个最最简单,最最小巧的 Hello world (一)用 Intell ...

  3. 【Linux】linux history命令执行后显示历史命令执行时间

    vim  ~/.bashrc 或者 ~/.bash_profile  或者 获取root权限修改vim /etc/profile 最后添加 export HISTTIMEFORMAT="%F ...

  4. java List接口二

    一 ArrayList集合 ArrayList集合数据存储的结构是数组结构.元素增删慢,查找快,由于日常开发中使用最多的 功能为查询数据.遍历数据,所以ArrayList是最常用的集合. 许多程序员开 ...

  5. ALGEBRA-1 向量空间

    向量空间对加法封闭 对数乘封闭 直和:表示的唯一性

  6. 2020-07-14:es用过冷热分离吗?假如现在有些数据热变冷,有些数据冷变热,怎么解决?

    福哥答案2020-07-14: 热变冷: 有x台机器tag设置为hot. 有y台机器tag设置为cool. hot集群中只存最近两天的. 有一个定时任务每天将前一天的索引标记为cool. es看到有新 ...

  7. 花式求解 LeetCode 279题-Perfect Squares

    原文地址 https://www.jianshu.com/p/2925f4d7511b 迫于就业的压力,不得不先放下 iOS 开发的学习,开始走上漫漫刷题路. 今天我想聊聊 LeetCode 上的第2 ...

  8. 简谈DFS

    所谓DFS就是“不撞南墙不回头”的一种搜索.其时间复杂度为O(V+E). 能算出从起点到终点的全部路径,在算法执行的过程中需要一个visit[vi]数组来维护每个结点的访问情况,这样就能避免重复访问. ...

  9. 关于数据库新建用户提示“用户、组或角色‘’XXX‘’在当前数据库中已已存在”的解决办法

    一般在还原数据库后,给这个数据库添加一个登录名时出现. 例如数据库备份文件中已经包含了用户abc,现在还原了数据库,然后发现现有数据库中没有abc这个用户,想要新建一个abc用户,作为该数据库的own ...

  10. 什么是BFC?看这一篇就够了

    BFC 定义 BFC(Block formatting context)直译为"块级格式化上下文".它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的 ...