tags:

views:

7784

answers:

3

In mysql, I do this:

select * 
from sometable
order by name
limit 10,20

In which case I get the 21st to the 30th rows (skip the first 20, give the next 10). The rows are selected after the order by, so it really starts on the 20th name alphabetically.

In Oracle, the only thing people mention is the rownum pseudo-column, but it is evaluated before order by, which means this:

select * 
from sometable
where rownum <= 10
order by name

will return a random set of 10 rows ordered by name, not usually what I want. Plus, you can't specify an offset.

So is there a way to do a mysql style limit clause in Oracle?

Thanks

+21  A: 

You can use a subquery for this like

select *
from  
( select * 
  from emp 
  order by sal desc ) 
where ROWNUM <= 5;

Have also a look at the topic On ROWNUM and limiting results at Oracle/AskTom for more information.

Update: To limit the result with both lower and upper bounds things get a bit more bloated with

select * from 
( select a.*, ROWNUM rnum from 
  ( <your_query_goes_here, with order by> ) a 
  where ROWNUM <= :MAX_ROW_TO_FETCH )
where rnum  >= :MIN_ROW_TO_FETCH;

(Copied from specified AskTom-article)

Kosi2801
+1 for the Ask Tom link
Nick Pierpoint
I was trying to get to that second one, but screwing it up royally. Thanks.
Mathieu Longtin
This is definitely the way to do it, but be aware (as the ask tom article says) the query performance degrades as your max rownum increases. This is a good solution for query results where you only want to see the first few pages, but if you are using this as a mechanism for code to page through a whole table you would be better off refactoring your code
Chris Gill
A: 

(untested) something like this may do the job

WITH
base AS
(
    select *                   -- get the table
    from sometable
    order by name              -- in the desired order
),
twenty AS
(
    select *                   -- get the first 30 rows
    from base
    where rownum < 30
    order by name              -- in the desired order
)
select *                       -- then get rows 21 .. 30
from twenty
where rownum > 20
order by name                  -- in the desired order

There is also the analytic function rank, that you can use to order by.

EvilTeach
+2  A: 

An analytic solution with only one nested query:

SELECT * FROM
(
   SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
) 
WHERE MyRow BETWEEN 10 AND 20;

Rank() could be substituted for Row_Number() but might return more records than you are expecting if there are duplicate values for name.

Leigh Riffel
I love analytics. You might want to clarify what the difference in behavior would be between Rank() and Row_Number().
Dave Costa
I'm not sure there would be a difference in this case.
Leigh Riffel
There is a difference between rank() and row_number() when there are ties. You see here an example with the differences between dense_rank, rank and row_number. http://www.adp-gmbh.ch/ora/sql/analytical/dense_rank_vs_rank_vs_row_number.html
tuinstoel
Indeed, not sure why I didn't think about duplicates. So, in this case if there are duplicate values for name then RANK could give more records than you are expecting therefore you should use Row_Number.
Leigh Riffel