Oracle中select子句取值先于order by子句执行而导致rownum伪列未按预期取值导致的问题
有这么一张表:
create table hytb(
id number(4,0) not null primary key,
padid nvarchar2(20) not null,
inputdate date not null,
dosid integer not null
)
可以这样给它充值:
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-23','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-26','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-23','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-27','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-28','yyyy-MM-dd'),'');
充完值是这样的结果集:
现在需要从中找出inputdate最近的三条记录(从图中目测是28-JAN-20,27-JAN-20,26-JAN-20),请问该怎么做?
首先可以利用row_number()函数:
select * from (select row_number() over (order by inputdate desc) as rn,hytb.* from hytb) a where a.rn<4
其次可以利用rownum伪列:
select * from (select rownum as rn,a.* from (select * from hytb order by inputdate desc) a) b where b.rn<4
这两种SQL都是正确的,可以互相验证。
但是,下面的sql却是错误的:
select * from (select rownum as rn,hytb.* from hytb order by inputdate desc) a where a.rn<4
执行结果如下:
为什么会出现这样的结果呢,让我们先看看其中子句select rownum as rn,hytb.* from hytb order by inputdate desc的执行结果:
可以发现,伪列和id是一样的,并没有按时间排。
究其原因,是因为select子句的执行顺序在order by之前,在sql:
select rownum as rn,hytb.* from hytb order by inputdate desc
里,首先执行的是
select rownum as rn,hytb.* from hytb
其次才是
order by inputdate desc
也就是说,伪列先于order by执行,或者说 select子句先于order by子句执行,由于rownum在select子句中,所以rownum伪列先于order by执行。
关于SQL子句的执行顺序,可以参考:https://database.51cto.com/art/202001/609727.htm
这就是问题所在。
突破藩篱的感觉真好。
--2020-03-10--
以下是上面实验用到的所有sql,贴出来以供参考:
create table hytb(
id number(4,0) not null primary key,
padid nvarchar2(20) not null,
inputdate date not null,
dosid integer not null
) insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-23','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-26','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-23','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-27','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-24','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-25','yyyy-MM-dd'),'');
insert into hytb(id,padid,inputdate,dosid) values('','',to_date('2020-01-28','yyyy-MM-dd'),''); commit; truncate table hytb select * from hytb --Correct
select * from (select rownum as rn,a.* from (select * from hytb order by inputdate desc) a) b where b.rn<4 select * from (select row_number() over (order by inputdate desc) as rn,hytb.* from hytb) a where a.rn<4 --Wrong
select * from (select rownum as rn,hytb.* from hytb order by inputdate desc) a where a.rn<4
Oracle中select子句取值先于order by子句执行而导致rownum伪列未按预期取值导致的问题的更多相关文章
- Oracle中ROWNUM伪列和ROWID伪列的用法与区别
做过Oracle分页的人都知道由于Oracle中没有像MySql中limit函数以及SQLServer中的top关键字等,所以只能通过伪列的方式去满足分页功能,在此,不谈分页方法,只从根本上去介绍这两 ...
- 1. 安装Oracle,配置环境 2. 实现查询From子句 3. 实现查询where子句 4. 实现查询order by子句
一.环境安装1. 登录:以管理员身份登录 sqlplus 登录名/密码 管理员身份登录:sqlplus system/1234562. 登录后,导入案例.下载scott.sql文件,执行下面一行的命令 ...
- Oracle 中select XX_id_seq.nextval from dual 什么意思呢?
说明 今天看别人的代码 ,遇见了 一条sql select ctg_fault_list_id_seq.nextval from dual 不懂意思,然后就研究了下 dual :是oracle ...
- 论MySQL中如何代替Oracle中select into new_table from old_table
v_receipt warehouse_receipt%ROWTYPE;-- 这里创建表类型,v_receipt复刻了warehouse_receipt的类型(相当于拥有了所有相同的字 ...
- oracle中 SELECT INTO 和INSERT INTO ... SELECT区别
在Oracle中,将一张表的数据复制到另外一个对象中.通常会有这两种方法:insert into select 和 select into from. 前者可以将select 出来的N行(0到任意数 ...
- Oracle中select使用别名
1 .将字段用as转换成别名. 2 .直接在字段的名字后面跟别名. 3 .在字段后面用双引号引起的别名. 我的朋友 大鬼不动 最近访客 fhwlj kochiyas 大極星 Alz__ deser ...
- Oracle中select 1和select *的区别
转自:https://www.linuxidc.com/Linux/2010-05/26202.htm 创建myt表并插入数据,如下: create table myt(name varchar2,c ...
- Oracle中Select语句完整的执行顺序
oracle Select语句完整的执行顺序: .from 子句组装来自不同数据源的数据: .where 子句基于指定的条件对记录行进行筛选: .group by子句将数据划分为多个分组: .使用聚集 ...
- Hive中SELECT TOP N的方法(order by与sort by的区别)
我想说的SELECT TOP N是取最大前N条或者最小前N条. Hive提供了limit关键字,再配合order by可以很容易地实现SELECT TOP N. 但是在Hive中order by只能使 ...
随机推荐
- Python 切分数组,将一个数组均匀切分成多个数组
Python 切分数组 将一个数组,均分为多个数组 代码 # -*- coding:utf-8 -*- # py3 def list_split(items, n): return [items[i: ...
- MSF常用命令备忘录
msf下的命令 set session x:设置要攻击的session #监听端口反弹PHP shell use exploit/multi/handler set payload php/meter ...
- LeetCode 91,点赞和反对五五开,这题是好是坏由你来评判
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第57篇文章,我们一起来看看LeetCode第91题,解码方法(Decode ways). 这道题官方给定的难度 ...
- win10下使用AIDA64建立副屏监控
写在前面: 最近刚攒了一台台式机,但是苦于没有太喜欢的温度监控插件,在贴吧里面看到有人用AIDA64做了一个副屏监控,感觉非常6,于是就开始了折腾之路. 需要的设备和软件: windows系统电脑一台 ...
- day7 地址 名片管理系统
1 无限循环 (while True) break 退出 人为设计的 ,并且有退除的出口 死循环 bug 错误 2.引用 数字型
- java中extends与implements的区别
学了java很久了,久不用之后给同学解决一个java问题的时候,就卡在这个标题上了. 下面是java中extends与implements的区别: 1. 在类的声明中,通过关键字extends来创建一 ...
- Typescript node starter 2.Router Middleware
Router 路由器对象是中间件和路由的一个独立实例.可以将它视为一个“迷你应用程序”,仅能够执行中间件和路由功能.每个Express应用程序都有一个内置的应用程序路由器. 路由器的行为类似于中间件本 ...
- JDBC驱动程序分类
JDBC驱动程序分类 JDBC驱动程序:各个数据库厂商根据JDBC的规范制作的 JDBC 实现类的类库 JDBC驱动程序总共有四种类型: 第一类:JDBC-ODBC桥. 第二类:部分本地API部分Ja ...
- Java并发篇
Java并发篇 作者:星晴(当地小有名气,小到只有自己知道的杰伦粉) 1. Java锁 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 Synchronized 同步锁 1.4.1 核心组件 ...
- 基于 abp vNext 微服务开发的敏捷应用构建平台 - 项目介绍
缘起 目前使用ABP框架已经将近3年了,大大小小的项目也陆陆续续做了很多.由于现有信息系统的架构模式是在底层的技术平台上直接构建信息系统并采用技术主导,使用业务无关的编程工具来开发信息系统的缺陷使得系 ...