17

How do you write a query where only a select number of rows are returned with either the highest or lowest column value.

i.e. A report with the 5 highest salaried employees?

APC
  • 144,005
  • 19
  • 170
  • 281
Trevor
  • 235
  • 1
  • 2
  • 6

5 Answers5

26

The best way to do this is with analytic functions, RANK() or DENSE_RANK() ...

SQL> select * from (
  2        select empno
  3               , sal
  4               , rank() over (order by sal desc) as rnk
  5        from emp)
  6  where rnk <= 5
  7  /

     EMPNO        SAL        RNK
---------- ---------- ----------
      7839       5000          1
      7788       3000          2
      7902       3000          2
      7566       2975          4
      8083       2850          5
      7698       2850          5

6 rows selected.

SQL>

DENSE_RANK() compresses the gaps when there is a tie:

SQL> select * from (
  2        select empno
  3               , sal
  4               , dense_rank() over (order by sal desc) as rnk
  5        from emp)
  6  where rnk <= 5
  7  /

     EMPNO        SAL        RNK
---------- ---------- ----------
      7839       5000          1
      7788       3000          2
      7902       3000          2
      7566       2975          3
      8083       2850          4
      7698       2850          4
      8070       2500          5

7 rows selected.

SQL>

Which behaviour you prefer depends upon your business requirements.

There is also the ROW_NUMBER() analytic function which we can use to return a precise number of rows. However, we should avoid using solutions based on row number unless the business logic is happy to arbitrarily truncate the result set in the event of a tie. There is a difference between asking for the five highest values and the first five records sorted by high values

There is also a non-analytic solution using the ROWNUM pseudo-column. This is clunky because ROWNUM is applied before the ORDER BY clause, which can lead to unexpected results. There is rarely any reason to use ROWNUM instead of ROW_NUMBER() or one of the ranking functions.

APC
  • 144,005
  • 19
  • 170
  • 281
  • You can use `QUALIFY ... <= 5` instead of wrapping it in another select. – lins314159 Feb 21 '10 at 23:16
  • @lins314159 - QUALIFY is not a construct which Oracle supports. – APC Feb 22 '10 at 01:24
  • I thought it did. Or is the link talking about some other Oracle product?`http://download.oracle.com/docs/cd/E12032_01/doc/epm.921/html_ir_studio/ir_studio-15-36.html` – lins314159 Feb 22 '10 at 01:58
  • That's the "Hyperion System 9 BI+ Interactive Reporting Interactive Reporting Studio" which looks like it supports more than Oracle standard SQL. – Jeffrey Kemp Feb 22 '10 at 02:50
13

Try this one:

SELECT * FROM 
    (SELECT field1, field2 FROM fields order by field1 desc) 
where rownum <= 5

Also take a look on this resource for a more detailed description on how rownum works.

qyb2zm302
  • 6,458
  • 2
  • 17
  • 17
road242
  • 2,492
  • 22
  • 30
4

Oracle 9i+ provides analytic functions:

All require the use of the OVER clause, which allows PARTITION BY and ORDER BY clauses to properly tune the ROW_NUMBER/RANK/DENSE_RANK value returned.

Prior to 9i, the only option was to work with ROWNUM - which incidentally is faster than using ROW_NUMBER (link).

OMG Ponies
  • 325,700
  • 82
  • 523
  • 502
  • Thanks. The OVER clause was new to me. +1 – road242 Feb 21 '10 at 21:18
  • Actually Oracle introduced the Analytic functions in 8i, but only as under the Enterprise Edition license. In 9i they came under the Standard Edition license. – APC Feb 21 '10 at 21:18
3

In Oracle 12c, this can be achieved using FETCH..FIRST ROWS..ONLY

To fetch the top 5 highest salaries.

 SELECT *
       FROM EMPLOYEES
   ORDER BY SALARY DESC
FETCH FIRST 5 ROWS ONLY;
Sundararaj Govindasamy
  • 8,180
  • 5
  • 44
  • 77
Kaushik Nayak
  • 30,772
  • 5
  • 32
  • 45
-1
Select emp_id , salary from employees
  Order by salary desc
  Limit 5;
slfan
  • 8,950
  • 115
  • 65
  • 78
Gowtham v
  • 1
  • 1
  • `LIMIT` is not oracle syntax. It is used in some other database though, such as mysql/mariadb/postgresql/sqlite syntax, per https://stackoverflow.com/a/595155/44862 – qyb2zm302 Oct 22 '18 at 19:04