简体   繁体   中英

oracle sql wih rownum <=

why below query is not giving results if I remove the < sign from query.Because even without < it must match with results?

Query used to get second max id value:

select min(id) 
from(
    select distinct id 
    from student 
    order by id desc
) 
where rownum <=2


student id 
1
2
3
4

Rownum has a special meaning in Oracle. It is increased with every row, but the optimizer knows that is increasing continuously and all consecutive rows must met the rownum condition. So if you specify rownum = 2 it will never occur since the first row is already rejected.

You can see this very nice if you do an explain plan on your query. It will show something like:

Plan for rownum <= :

COUNT STOPKEY       

Plan for rownum = :

FILTER

A ROWNUM value is not assigned permanently to a row (this is a common misconception). A row in a table does not have a number; you cannot ask for row 2 or 3 from a table click Here for more Info.

This is from the link provided:

Also confusing to many people is when a ROWNUM value is actually assigned. A ROWNUM value is assigned to a row after it passes the predicate phase of the query but before the query does any sorting or aggregation. Also, a ROWNUM value is incremented only after it is assigned, which is why the following query will never return a row:

select * 
 from t 
 where ROWNUM > 1;

Because ROWNUM > 1 is not true for the first row, ROWNUM does not advance to 2. Hence, no ROWNUM value ever gets to be greater than 1. Consider a query with this structure:

select ..., ROWNUM
from t
where <where clause>
group by <columns>
having <having clause>
order by <columns>;

I think this is the query you are looking for:

select id
from (select distinct id
      from student
      order by id desc
     ) t
where rownum <= 2;

Oracle processes the rownum before the order by , so you need a subquery to get the first two rows. The min() was forcing an aggregation that returned only one result, but before the rownum was applied.

If you actually want only the second value, you need an additional layer of subqueries:

select min(id)
from (select id
      from (select distinct id
            from student
            order by id desc
           ) t
      where rownum <= 2
     ) t;

However, I would do:

select id
from (select id, dense_rank() over (order by id) as seqnum
      from student
     ) t
where seqnum = 2;

Why not just use

select  id
from    ( select distinct id
          ,      row_number() over (order by id desc) x
          from   student
        )
where   x = 2

Or even really bad. Getting the count and index :)

select  id
from    ( select id
          ,      row_number() over (order by id desc) idx
          ,      sum(1) over (order by null) cnt
          from   student
          group
          by     id
        )
where   idx = cnt - 1 -- get the pre-last

Or

where   idx = cnt - 2 -- get the 2nd-last

Or

where   idx = 3 -- get the 3rd

订购asc而不是desc

select id from student where rownum <=2 order by id asc;

Try this

SELECT * 
FROM (
  SELECT id, row_number() over (order by id asc) row_num
  FROM student
     ) AS T
WHERE row_num = 2 -- or 3 ... n

ROW_NUMBER

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM