La meilleure façon de le faire est d'utiliser des fonctions analytiques, RANK() ou 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 les écarts en cas d'égalité :
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>
Le comportement que vous préférez dépend des besoins de votre entreprise.
Il existe également la fonction analytique ROW_NUMBER() que nous pouvons utiliser pour renvoyer un nombre précis de lignes. Cependant, nous devons éviter d'utiliser des solutions basées sur le numéro de ligne à moins que la logique métier ne se contente de tronquer arbitrairement le jeu de résultats en cas d'égalité. Il y a une différence entre demander les cinq valeurs les plus élevées et les cinq premiers enregistrements triés par valeurs élevées
Il existe également une solution non analytique utilisant la pseudo-colonne ROWNUM. C'est maladroit car ROWNUM est appliqué avant la clause ORDER BY, ce qui peut entraîner des résultats inattendus. Il y a rarement une raison d'utiliser ROWNUM au lieu de ROW_NUMBER() ou l'une des fonctions de classement.