Janet Linsy wrote:
> 
> Hi,
> 
> I have a table like this:
> 
> SQL> select * from test;
> 
>         ID      PRICE
> ---------- ----------
>          1          1
>          1          3
>          1          4
>          1          5
>          1          6
> 
> I need to get the second largest price and I was using
> the ROWNUM.
> 
> For the following statement, the result makes sense:
> SQL> select * from test where rownum <  (select
> count(*) -1 from test);
> 
>         ID      PRICE
> ---------- ----------
>          1          1
>          2          3
>          3          4
> 
> But the rest twos didn't return anything:
> 
> SQL> select * from test where rownum=(select count(*)
> -1 from test); -- supposed to return 5 ???
> 
> no rows selected
> 
> SQL> select * from test where rownum > (select
> count(*) -1 from test); -- supposed to return 6 ???
> 
> no rows selected
> 
> I vaguely remember that ROWNUM only works in < case,
> why is that?  Thank you!

Janet,

The reason is that it is computed on the fly as rows are returned (i.e.
pass all filters). Rownum=1 works, but rownum=2 cannot, since to have a
rownum value of 2 you should have first displayed a rownum 1. Catch 22.
< or <= works, for the same reason.

To answer your question, you have several ways to do it.

I have a test table slightly different from yours :

SQL> select * from test;

        ID      PRICE
---------- ----------
         1        1.5
         2        1.8
         3          2
         4        1.9
         5        1.3

The rownum is computed BEFORE any ORDER BY :
  1  select rownum, id, price
  2* from test
SQL> /

    ROWNUM         ID      PRICE
---------- ---------- ----------
         1          1        1.5
         2          2        1.8
         3          3          2
         4          4        1.9
         5          5        1.3

  1  select rownum, id, price
  2  from test
  3* order by price desc
SQL> /

    ROWNUM         ID      PRICE
---------- ---------- ----------
         3          3          2
         4          4        1.9
         2          2        1.8
         1          1        1.5
         5          5        1.3


However, you can cheat by having the ORDER BY performed inside an
in-line view :
  1  select rownum, x.id, x.price
  2  from (select id, price
  3        from test
  4*       order by price desc) x
SQL> /

    ROWNUM         ID      PRICE
---------- ---------- ----------
         1          3          2
         2          4        1.9
         3          2        1.8
         4          1        1.5
         5          5        1.3

By nesting one degree deeper, you can answer your question (well,
fairly) easily :
  1  select y.id, y.price
  2  from (select rownum price_rank, x.id, x.price
  3        from (select id, price
  4              from test
  5              order by price desc) x) y
  6* where y.price_rank = 2
SQL> /

        ID      PRICE
---------- ----------
         4        1.9

Here, the rownum has been computed on the fly, but INSIDE the least
nested in-line view, so it appears as 'static' data at the outside level
and then = or > works.

Another way to do it is this :

  1  select x.id, x.price
  2  from (select id, price
  3        from test
  4        order by price desc) x
  5  where x.price < (select max(price)
  6                   from test)
  7*   and rownum = 1
SQL> /

        ID      PRICE
---------- ----------
         4        1.9

which is likely to be more efficient, especially if PRICE is indexed.

I have tried to have a go with the RANK() analytical function, but
without much success :-(.

HTH,

Stephane Faroult
Oriole Ltd
-- 
Please see the official ORACLE-L FAQ: http://www.orafaq.com
-- 
Author: Stephane Faroult
  INET: [EMAIL PROTECTED]

Fat City Network Services    -- (858) 538-5051  FAX: (858) 538-5051
San Diego, California        -- Public Internet access / Mailing Lists
--------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: [EMAIL PROTECTED] (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).

Reply via email to