Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I limit the number of rows returned by an Oracle query after ordering?

Is there a way to make an Oracle query behave like it contains a MySQL limit clause?

In MySQL, I can do this:

select *  from sometable order by name limit 20,10 

to 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 ten rows ordered by name, which is not usually what I want. It also doesn't allow for specifying an offset.

like image 625
Mathieu Longtin Avatar asked Jan 22 '09 19:01

Mathieu Longtin


People also ask

How do I restrict the number of rows in Oracle?

There are two approaches to limit the number of rows returned by an Oracle query. Using the rownum value to limit the number of rows, as well as the OFFSET and FETCH keywords to limit the number of rows. The row limiting clause is supported in Oracle queries beginning with Oracle 12c R1 (12.1).

How do I limit the number of rows returned in a query?

Limit the Rows Returned in a SQL Server Query by using the TOP Clause. In SQL Server, you can use the TOP clause to limit the rows returned from a query result set. This clause provides similar functionality to LIMIT in MySQL, and ROWNUM in Oracle, although there are differences in how each of these work.

How do I limit SQL query results?

The SQL LIMIT clause constrains the number of rows returned by a SELECT statement. For Microsoft databases like SQL Server or MSAccess, you can use the SELECT TOP statement to limit your results, which is Microsoft's proprietary equivalent to the SELECT LIMIT statement.

Does limit work in Oracle?

Oracle Database does not have the LIMIT clause.


2 Answers

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)

Update 2: Starting with Oracle 12c (12.1) there is a syntax available to limit rows or start at offsets.

SELECT *  FROM   sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; 

See this answer for more examples. Thanks to Krumia for the hint.

like image 79
Kosi2801 Avatar answered Sep 24 '22 06:09

Kosi2801


Starting from Oracle 12c R1 (12.1), there is a row limiting clause. It does not use familiar LIMIT syntax, but it can do the job better with more options. You can find the full syntax here. (Also read more on how this works internally in Oracle in this answer).

To answer the original question, here's the query:

SELECT *  FROM   sometable ORDER BY name OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; 

(For earlier Oracle versions, please refer to other answers in this question)


Examples:

Following examples were quoted from linked page, in the hope of preventing link rot.

Setup

CREATE TABLE rownum_order_test (   val  NUMBER );  INSERT ALL   INTO rownum_order_test SELECT level FROM   dual CONNECT BY level <= 10;  COMMIT; 

What's in the table?

SELECT val FROM   rownum_order_test ORDER BY val;         VAL ----------          1          1          2          2          3          3          4          4          5          5          6          6          7          7          8          8          9          9         10         10  20 rows selected. 

Get first N rows

SELECT val FROM   rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY;         VAL ----------         10         10          9          9          8  5 rows selected. 

Get first N rows, if Nth row has ties, get all the tied rows

SELECT val FROM   rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS WITH TIES;         VAL ----------         10         10          9          9          8          8  6 rows selected. 

Top x% of rows

SELECT val FROM   rownum_order_test ORDER BY val FETCH FIRST 20 PERCENT ROWS ONLY;         VAL ----------          1          1          2          2  4 rows selected. 

Using an offset, very useful for pagination

SELECT val FROM   rownum_order_test ORDER BY val OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY;         VAL ----------          3          3          4          4  4 rows selected. 

You can combine offset with percentages

SELECT val FROM   rownum_order_test ORDER BY val OFFSET 4 ROWS FETCH NEXT 20 PERCENT ROWS ONLY;         VAL ----------          3          3          4          4  4 rows selected. 
like image 24
sampathsris Avatar answered Sep 23 '22 06:09

sampathsris