简体   繁体   中英

Oracle SQL Query rownum inconsistent

The below queries results seem inconsistent to me.

select OUTCOME from (select OUTCOME, NUMBER1 
                       from TASK
                       order by TASK_NUMBER desc)
  where NUMBER1 = 1500

Returns 3 rows

1: (null)
2: Expected Outcome
3: Some other previous outcome

Added ROWNUM=2 , which is the row I want.

select OUTCOME from (select OUTCOME, NUMBER1
                       from TASK
                       order by TASK_NUMBER desc)
  where NUMBER1 = 1500 and
        ROWNUM=2

Result is 1: (null) rather than the expected 1: Expected Outcome

If I try with ROWNUM=1 I receive, what I'd expect in that instance which is 1: (null)

How can I retrieve that middle row consistently?

A query with WHERE ROWNUM = X or WHERE ROWNUM > X doesn't make sense. This is because a ROWNUM value is assigned to a row during the predicate evaluation and gets incremented only after a row passes the WHERE clause.

source

select OUTCOME from
  (select OUTCOME, NUMBER1, ROWNUM RN from TASK order by TASK_NUMBER desc)
where NUMBER1 = 1500 and RN=2

EDIT

Actually, above solution is false, because ROWNUM will be assigned before ORDER BY clause. Without using ROW_NUMBER() (like in zaratustra's answer ), the right solution is:

select OUTCOME from (
  select ROWNUM RN, OUTCOME, NUMBER1
    from (select OUTCOME, NUMBER1 from TASK order by TASK_NUMBER desc)
) where NUMBER1 = 1500 and RN=2

ROWNUM is unpredictable in your case and unreachable for cases rownum = n (n > 1) or rownum > n ( n is any natural number), you have to use ROW_NUMBER() like this:

select OUTCOME 
  from (
        select OUTCOME
             , NUMBER1
             , ROW_NUMBER() OVER(order by TASK_NUMBER desc) rn 
          from TASK
       ) 
 where NUMBER1 = 1500 
   and rn=2

ROWNUM = 2 (or ROWNUM > 1 ) will always cause no rows to be found. ROWNUM is generated as rows are output from the query, after all conditions are evaluated ; thus, the first row output from the query is assigned ROWNUM 1, the next gets ROWNUM 2, etc. Thus, asking for the row where ROWNUM = 2 is equivalent to asking get me the second row emitted from the query which will never occur, because the ROWNUM = 2 comparison means there will never be a first row emitted from the query, which would have ROWNUM = 1 .

Thus, I believe that the only workable comparisons on ROWNUM are:

= 1
>= 1
< n
BETWEEN 1 and n

One way to work around this is to rewrite your query as:

select OUTCOME from (select OUTCOME, NUMBER1, ROWNUM as RNUM
                       from TASK
                       order by TASK_NUMBER desc)
  where NUMBER1 = 1500 and
        RNUM = 2

Here we create a temp column named RNUM in the inner query, assigning it the value of ROWNUM as generated by the inner query. In the outer query we test RNUM to see if it's equal to 2.

Share and enjoy.

Row numbers are assigned at the runtime and you can fetch a particular row by matching the rownum. You can achieve this by including the rownum in your sub-query. Please use the query below:

select  OUTCOME from (select OUTCOME, NUMBER1,ROWNUM RID from TASK order by TASK_NUMBER desc) where NUMBER1 = 1500 and RID=2

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