zoukankan      html  css  js  c++  java
  • 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('1','001',to_date('2020-01-23','yyyy-MM-dd'),'398');
    insert into hytb(id,padid,inputdate,dosid) values('2','001',to_date('2020-01-24','yyyy-MM-dd'),'442');
    insert into hytb(id,padid,inputdate,dosid) values('3','001',to_date('2020-01-25','yyyy-MM-dd'),'90');
    insert into hytb(id,padid,inputdate,dosid) values('4','001',to_date('2020-01-26','yyyy-MM-dd'),'178');
    insert into hytb(id,padid,inputdate,dosid) values('5','002',to_date('2020-01-23','yyyy-MM-dd'),'444');
    insert into hytb(id,padid,inputdate,dosid) values('6','002',to_date('2020-01-24','yyyy-MM-dd'),'15');
    insert into hytb(id,padid,inputdate,dosid) values('7','002',to_date('2020-01-25','yyyy-MM-dd'),'145');
    insert into hytb(id,padid,inputdate,dosid) values('8','002',to_date('2020-01-27','yyyy-MM-dd'),'196');
    insert into hytb(id,padid,inputdate,dosid) values('9','003',to_date('2020-01-24','yyyy-MM-dd'),'22');
    insert into hytb(id,padid,inputdate,dosid) values('10','003',to_date('2020-01-25','yyyy-MM-dd'),'22');
    insert into hytb(id,padid,inputdate,dosid) values('11','004',to_date('2020-01-24','yyyy-MM-dd'),'33');
    insert into hytb(id,padid,inputdate,dosid) values('12','004',to_date('2020-01-25','yyyy-MM-dd'),'33');
    insert into hytb(id,padid,inputdate,dosid) values('13','004',to_date('2020-01-28','yyyy-MM-dd'),'33');

    充完值是这样的结果集:

    现在需要从中找出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('1','001',to_date('2020-01-23','yyyy-MM-dd'),'398');
    insert into hytb(id,padid,inputdate,dosid) values('2','001',to_date('2020-01-24','yyyy-MM-dd'),'442');
    insert into hytb(id,padid,inputdate,dosid) values('3','001',to_date('2020-01-25','yyyy-MM-dd'),'90');
    insert into hytb(id,padid,inputdate,dosid) values('4','001',to_date('2020-01-26','yyyy-MM-dd'),'178');
    insert into hytb(id,padid,inputdate,dosid) values('5','002',to_date('2020-01-23','yyyy-MM-dd'),'444');
    insert into hytb(id,padid,inputdate,dosid) values('6','002',to_date('2020-01-24','yyyy-MM-dd'),'15');
    insert into hytb(id,padid,inputdate,dosid) values('7','002',to_date('2020-01-25','yyyy-MM-dd'),'145');
    insert into hytb(id,padid,inputdate,dosid) values('8','002',to_date('2020-01-27','yyyy-MM-dd'),'196');
    insert into hytb(id,padid,inputdate,dosid) values('9','003',to_date('2020-01-24','yyyy-MM-dd'),'22');
    insert into hytb(id,padid,inputdate,dosid) values('10','003',to_date('2020-01-25','yyyy-MM-dd'),'22');
    insert into hytb(id,padid,inputdate,dosid) values('11','004',to_date('2020-01-24','yyyy-MM-dd'),'33');
    insert into hytb(id,padid,inputdate,dosid) values('12','004',to_date('2020-01-25','yyyy-MM-dd'),'33');
    insert into hytb(id,padid,inputdate,dosid) values('13','004',to_date('2020-01-28','yyyy-MM-dd'),'33');
    
    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
  • 相关阅读:
    Eclipse中创建新的Spring Boot项目
    解决win下无法ping通VM虚拟机CentOS系统的方法
    32位centos下安装jdk1.7报Permission denied处理方式
    Windows下安装HBase
    15个nosql数据库
    查看软件的安装路径
    IP地址 网段的划分
    签名算法
    CentOS开启FTP及配置用户
    CentOS 5.5安装SVN(Subversion)
  • 原文地址:https://www.cnblogs.com/heyang78/p/12455930.html
Copyright © 2011-2022 走看看