oracle的rownum分析

create table girls(
       id varchar2(20),
       name varchar2(20),
       salary number,
       type char
);
insert into girls values ('g_1', '张雨绮', '10000', '1');
insert into girls values ('g_2', '迪丽热巴', '30000', '1');
insert into girls values ('g_4', '心乱如麻', '20000', '0');
insert into girls values ('g_5', '沉鱼落雁', '5000', '0');
insert into girls values ('g_6', '闭月羞花', '3000', '0');

  一般来说我们利用rownum,有两点需求,如果我们想获取前两条数据 直接rownum < 3就可以了;但是如果我们想获取第三条和第四条数据,此时我们想写rownum > 2 and rownum < 5我们是无法查询到任何一条数据的,下面就rownum进行分析。
        rownum可以直接 > 0不会报错,但是没有意义它不能过滤掉任何一行数据,> 比0大的数,则会过滤掉所有数据。试想从表里第一条数据开始,如果这条数据对应Object满足where条件,则放入一个Set<Object>,这里的Object就是每一行数据加上了一个rownum属性,如果我们是rownum > 0,第一个Object的rownum = 1满足可以放进Set,第二行的rownum = 2也是满足放进Set,所以是没有意义的; 如果我们是rownum > 1, 试想第一行数据,对应的Object的rownum一开始就是1,肯定不满足条件的,所以此时第一行数据被过滤的,然后开始获取第二条数据的Object准备放入Set,此时的rownum还是1,依然是不能放进Set,所以所有的数据都会被过滤掉,我们最后肯定是没法查到任何一条的。
        回到一开始的问题,想要获取第三条和第四条数据,可以把第一个rownum作为字段,在第二个select过滤时,根据这个定死的rownum来过滤,此时里层select对应的rownum我们必须取一个别名,如果不取的话,在最外层我们使用这个属性时肯定是b.rownum来调用的,但是sql解析时,不知道你这是调用的外层select的隐藏的rownum还是里层我们定死的rownum,毕竟字段名都是一样的,没法区分
select a.*, rownum from girls a;
select a.*, rownum from girls a where rownum < 3;
select a.*, rownum from girls a where rownum > 2 and rownum < 4;
select b.* from (select a.*, rownum rn from girls a ) b where b.rn > 2 and b.rn < 5
        上面谈的是直接对rownum进行截取,这样的场景一般用于分页查询,可能我们会在分页之前进行排序,下面就这样的场景进行分析。
        首先,我们得先确认,rownum的值是在from获取总集合数据,where过滤不要的数据后,就以前定死了的,下面我们可能对数据进行操作,比如分组,排序。这时的rownum,我们其实可以把它看作一个正常的字段了,下面的一个排序,一个分组就可以看出来,rownum在where之后就已经定死了的
select a.*,rownum from girls a order by salary;
select max(rownum) from girls group by type;
        现在假如我想获取身价排名3,4的人,也就是张雨绮,心乱如麻。
第一个select排序,第二个select加上了等同于身价顺序的rownum,第三个select根据定死的第二个select的rownum进行截取
select c.name from (select b.*, rownum b_rn from (select a.* from girls a order by salary) b) c where c.b_rn > 2 and c.b_rn < 5;
        优化分析:试想万一有10000的人,但是我只想获取第3,第4,第三个的select我们还是对10000个人进行操作截取,既然rownum < ?我们是可以直接用的,那干嘛为啥不能在第二个select排序时,就进行截取呢,rownum < 5,之后的第三个select操作的数据,肯定是只有4行数据的。
select c.name from (select b.*, rownum b_rn from (select a.* from girls a order by salary) b where rownum < 5) c where c.b_rn > 2;  这里我一开始写的是b.b_rn < 5,结果报错找不到b.b_rn,这里涉及到了sql执行规则,别名还没有生效。

猜你喜欢

转载自blog.csdn.net/blossomfzq/article/details/82892564