要求前三名,MySQL中有order by排序,limit限制数量,结果很容易得到,而且limit的执行顺序也在order by之后,写出的sql高效易懂而不易出错。

但在oracle中,由于没有limit子句,人们喜欢求助于rownum伪列,但是,因为rownum身处select子句中,而select子句的执行顺序先于order by,因此只有order by比rownum更深一个层次,这样得到的伪列才有效,否则如果rownum和order by处于同一层次,这时的伪列是无效的!如果忘了这一点,很容易写成错误的sql语句,下面将就此举例说明:

待测试的表结构:

create table tb_student01(
id number(4,0) not null primary key,
name nvarchar2(20) not null,
score number(3,0) not null)

充值语句(注意我故意打乱了插入顺序,就是不想在sql写错时还能因为插入顺序的关系而蒙到正确结果):

insert into tb_student01(id,name,score) values('','张三',77);
insert into tb_student01(id,name,score) values('','李四',88);
insert into tb_student01(id,name,score) values('','Felix',10);
insert into tb_student01(id,name,score) values('','赵六',15);
insert into tb_student01(id,name,score) values('','孙七',67);
insert into tb_student01(id,name,score) values('','钱八',37);
insert into tb_student01(id,name,score) values('','Andy',67);
insert into tb_student01(id,name,score) values('','Bill',98);
insert into tb_student01(id,name,score) values('','王五',100);
insert into tb_student01(id,name,score) values('','Cindy',25);
insert into tb_student01(id,name,score) values('','Douglas',64);
insert into tb_student01(id,name,score) values('','Eliot',99);

稍稍目测一下,100分的王五,99分的Eliot,98分的Bill将是期望的三甲。

首先我们看下面的SQL语句会是什么结果:

select rownum as rn,a.* from tb_student01 a order by a.score desc
SQL> select rownum as rn,a.* from tb_student01 a order by a.score desc;

        RN         ID NAME                                          SCORE
---------- ---------- ---------------------------------------- ----------
9 9 王五 100
12 5 Eliot 99
8 2 Bill 98
2 8 李四 88
1 7 张三 77
5 11 孙七 67
7 1 Andy 67
11 4 Douglas 64
6 12 钱八 37
10 3 Cindy 25
4 10 赵六 15 RN ID NAME SCORE
---------- ---------- ---------------------------------------- ----------
3 6 Felix 10 已选择12行。 已用时间: 00: 00: 00.00

从上面我们就能看出王五的rn值不是1而是9,Eliot的rn值不是2而是12,Bill的rn值不是3而是8!

发生这种情况的原因是rownum身处的select子句执行顺序是高于order by的,这导致了排序前rownum就按初始的插入顺序被赋上了值。

再用rn值进行筛选,得到的结果让人瞠目结舌:

select b.* from
(select rownum as rn,a.* from tb_student01 a order by a.score desc) b
where b.rn<4
SQL> select b.* from
2 (select rownum as rn,a.* from tb_student01 a order by a.score desc) b
3 where b.rn<4; RN ID NAME SCORE
---------- ---------- ---------------------------------------- ----------
2 8 李四 88
1 7 张三 77
3 6 Felix 10 已用时间: 00: 00: 00.01

三甲中不仅没有90分以上的,连考10分的Felix都被放到了三甲里,学生们如果知道真实原因会写完姓名后就抢先交卷,因为越早被批改,记录就越早出现在数据库中,也就越有可能位列三甲!这是多么荒唐的事情!

为了杜绝这种荒诞,我们必须重写sql,其中要点是先按分数排序再附上伪列。

首先排序:

select a.* from tb_student01 a order by a.score desc
SQL> select a.* from tb_student01 a order by a.score desc;

        ID NAME                                          SCORE
---------- ---------------------------------------- ----------
9 王五 100
5 Eliot 99
2 Bill 98
8 李四 88
7 张三 77
11 孙七 67
1 Andy 67
4 Douglas 64
12 钱八 37
3 Cindy 25
10 赵六 15 ID NAME SCORE
---------- ---------------------------------------- ----------
6 Felix 10 已选择12行。 已用时间: 00: 00: 00.01

其次,再附上伪列:

SQL> select rownum as rn,b.* from
2 (select a.* from tb_student01 a order by a.score desc) b ; RN ID NAME SCORE
---------- ---------- ---------------------------------------- ----------
1 9 王五 100
2 5 Eliot 99
3 2 Bill 98
4 8 李四 88
5 7 张三 77
6 11 孙七 67
7 1 Andy 67
8 4 Douglas 64
9 12 钱八 37
10 3 Cindy 25
11 10 赵六 15 RN ID NAME SCORE
---------- ---------- ---------------------------------------- ----------
12 6 Felix 10 已选择12行。 已用时间: 00: 00: 00.01

最后,对rn值进行筛选就得到最终结果了:

SQL> select c.* from
2 ( select rownum as rn,b.* from
3 (select a.* from tb_student01 a order by a.score desc) b ) c
4 where c.rn<4; RN ID NAME SCORE
---------- ---------- ---------------------------------------- ----------
1 9 王五 100
2 5 Eliot 99
3 2 Bill 98 已用时间: 00: 00: 00.01

这个结果和预期值是一致的,所以最终查询三甲的SQL是:

select c.* from
( select rownum as rn,b.* from
(select a.* from tb_student01 a order by a.score desc) b ) c
where c.rn<4

当然,不借助rownum也可以得到正确结果,比如说分析函数rank():

SQL:

select b.* from
(select rank() over (order by score desc) as rn,a.* from tb_student01 a ) b
where b.rn<4

执行结果:

SQL> select b.* from
2 (select rank() over (order by score desc) as rn,a.* from tb_student01 a ) b
3 where b.rn<4; RN ID NAME SCORE
---------- ---------- ---------------------------------------- ----------
1 9 王五 100
2 5 Eliot 99
3 2 Bill 98 已用时间: 00: 00: 00.00

或是借助row_number函数

SQL:

select b.* from
(select row_number() over (order by score desc) as rn,a.* from tb_student01 a ) b
where b.rn<4

执行结果:

SQL> select b.* from
2 (select row_number() over (order by score desc) as rn,a.* from tb_student01 a ) b
3 where b.rn<4; RN ID NAME SCORE
---------- ---------- ---------------------------------------- ----------
1 9 王五 100
2 5 Eliot 99
3 2 Bill 98 已用时间: 00: 00: 00.00

--2020年3月28日--

以上用到的全部SQL:

create table tb_student01(
id number(4,0) not null primary key,
name nvarchar2(20) not null,
score number(3,0) not null) insert into tb_student01(id,name,score) values('','张三',77);
insert into tb_student01(id,name,score) values('','李四',88);
insert into tb_student01(id,name,score) values('','Felix',10);
insert into tb_student01(id,name,score) values('','赵六',15);
insert into tb_student01(id,name,score) values('','孙七',67);
insert into tb_student01(id,name,score) values('','钱八',37);
insert into tb_student01(id,name,score) values('','Andy',67);
insert into tb_student01(id,name,score) values('','Bill',98);
insert into tb_student01(id,name,score) values('','王五',100);
insert into tb_student01(id,name,score) values('','Cindy',25);
insert into tb_student01(id,name,score) values('','Douglas',64);
insert into tb_student01(id,name,score) values('','Eliot',99); Wrong:
select rownum as rn,a.* from tb_student01 a order by a.score desc select b.* from
(select rownum as rn,a.* from tb_student01 a order by a.score desc) b
where b.rn<4 Correct:
select a.* from tb_student01 a order by a.score desc select rownum as rn,b.* from
(select a.* from tb_student01 a order by a.score desc) b select c.* from
( select rownum as rn,b.* from
(select a.* from tb_student01 a order by a.score desc) b ) c
where c.rn<4 select rank() over (order by score desc) as rn,a.* from tb_student01 a select b.* from
(select rank() over (order by score desc) as rn,a.* from tb_student01 a ) b
where b.rn<4 或是row_number函数
select b.* from
(select row_number() over (order by score desc) as rn,a.* from tb_student01 a ) b
where b.rn<4

借助rownum中求Oracle表中前三名(三甲:状元榜眼探花)的方法(总计三种方法,以讲述rownum的使用为主)的更多相关文章

  1. JavaScript中的方法事件和函数的方法的三种方法

    js中的很多事件  而事件相对应的就是方法(函数 )那么今天所说的就是这三种方法      已onclick事件为例 1: 基本方法 <div id="a" onclick= ...

  2. Java_Swing中让窗口居中显示的方法(三种方法)

    方法一: int windowWidth = frame.getWidth(); // 获得窗口宽    int windowHeight = frame.getHeight(); // 获得窗口高 ...

  3. ASP.NET MVC 中将数据从View传递到控制器中的三种方法(表单数据绑定)

    http://www.cnblogs.com/zyqgold/archive/2010/11/22/1884779.html 在ASP.NET MVC框架中,将视图中的数据传递到控制器中,主要通过发送 ...

  4. js replace 全局替换 以表单的方式提交参数 判断是否为ie浏览器 将jquery.qqFace.js表情转换成微信的字符码 手机端省市区联动 新字体引用本地运行可以获得,放到服务器上报404 C#提取html中的汉字 MVC几种找不到资源的解决方式 使用Windows服务定时去执行一个方法的三种方式

    js replace 全局替换   js 的replace 默认替换只替换第一个匹配的字符,如果字符串有超过两个以上的对应字符就无法进行替换,这时候就要进行一点操作,进行全部替换. <scrip ...

  5. 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理

    服务器文档下载zip格式   刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...

  6. mysql分表的三种方法

    先说一下为什么要分表当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间.根据个人经验,mysql执行一 ...

  7. Oracle数据库备份与恢复的三种方法

    转自blueskys567原文Oracle数据库备份与恢复的三种方法, 2006-10. 有删改 Oracle数据库有三种标准的备份方法,它们分别是导出/导入(EXP/IMP).热备份和冷备份. 导出 ...

  8. C#中??和?分别是什么意思? 在ASP.NET开发中一些单词的标准缩写 C#SESSION丢失问题的解决办法 在C#中INTERFACE与ABSTRACT CLASS的区别 SQL命令语句小技巧 JQUERY判断CHECKBOX是否选中三种方法 JS中!=、==、!==、===的用法和区别 在对象比较中,对象相等和对象一致分别指的是什么?

    C#中??和?分别是什么意思? 在C#中??和?分别是什么意思? 1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; ...

  9. 【SQL】Oracle分页查询的三种方法

    [SQL]Oracle分页查询的三种方法 采用伪列 rownum 查询前10条记录 ? 1 2 3 4 5 6 7 8 9 10 11 [sql] select * from t_user t whe ...

随机推荐

  1. Spring IOC 剖析

    模拟实现 Spring Ioc 控制反转功能 使用 => 原理 => 源码 => 模拟实现 使用:了解 原理:熟悉 源码 And 模拟实现: 精通 对照 Spring 功能点 Spr ...

  2. 通过java程序(JSch)运行远程linux主机上的shell脚本

    如果您看完文章之后,觉得对您有帮助,请帮我点个赞,您的支持是我不竭的创作动力! 如果您看完文章之后,觉得对您有帮助,请帮我点个赞,您的支持是我不竭的创作动力! 如果您看完文章之后,觉得对您有帮助,请帮 ...

  3. klassVtable与klassItable

    klassVtable与klassItable类用来实现Java方法的多态,也可以叫动态绑定,是指在应用执行期间通过判断接受对象的实际类型,根据实际类型调用对应的方法.C++为了实现多态,在对象中嵌入 ...

  4. CSS 定位总结

    目录 元素显示模式 元素模式 元素显示模式转换 CSS定位机制 静态定位static 相对定位relative 绝对定位absolute 固定定位fixed 粘性定位sticky 定位小结一图流 CS ...

  5. C++游戏(大型PC端枪战游戏)服务器架构

    实习期间深入参与到某大型pc端枪战游戏的后端开发中,此游戏由著名游戏工作室编写,代码可读性极高,自由时间对游戏后台代码进行了深入研究,在满足自身工作需要的同时对游戏后台的架构也有了理解,记录在此,以便 ...

  6. 2020-04-09:TCP的四次挥手中为什么要有TIME_WAIT状态?

    TIME_WAIT状态存在有两个原因.<1>可靠终止TCP连接.如果最后一个ACK报文因为网络原因被丢弃,此时server因为没有收到ACK而超时重传FIN报文,处于TIME_WAIT状态 ...

  7. C#LeetCode刷题之#459-重复的子字符串(Repeated Substring Pattern)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3945 访问. 给定一个非空的字符串,判断它是否可以由它的一个子串 ...

  8. Vue $nextTick的一个使用场景

    $nextTick 官方解释 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM 使用场景 在页面上有2个表单元素和2个按钮 btnRequiredFi ...

  9. myBatis源码解析-类型转换篇(5)

    前言 开始分析Type包前,说明下使用场景.数据构建语句使用PreparedStatement,需要输入的是jdbc类型,但我们一般写的是java类型.同理,数据库结果集返回的是jdbc类型,而我们需 ...

  10. 机器学习 | 详解GBDT在分类场景中的应用原理与公式推导

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第31篇文章,我们一起继续来聊聊GBDT模型. 在上一篇文章当中,我们学习了GBDT这个模型在回归问题当中的原理.GBD ...