La mejor manera de hacer esto es con funciones analíticas, RANK() o 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() comprime los huecos cuando hay un empate:
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>
El comportamiento que prefiera depende de los requisitos de su negocio.
También existe la función analítica ROW_NUMBER() que podemos usar para devolver un número preciso de filas. Sin embargo, debemos evitar el uso de soluciones basadas en el número de fila, a menos que la lógica comercial esté dispuesta a truncar arbitrariamente el conjunto de resultados en caso de empate. Hay una diferencia entre pedir los cinco valores más altos y los primeros cinco registros ordenados por valores altos
También existe una solución no analítica que utiliza la pseudocolumna ROWNUM. Esto es torpe porque ROWNUM se aplica antes de la cláusula ORDER BY, lo que puede generar resultados inesperados. Rara vez hay alguna razón para usar ROWNUM en lugar de ROW_NUMBER() o una de las funciones de clasificación.