Database 12c et normalisation SQL

Une des grandes nouveautés d’Oracle Database 12c en termes de normalisation SQL est sans aucun doute l’introduction de la clause FETCH dans un ordre SELECT pour en restreindre le nombre d’enregistrements remontés.
Dans la plupart des SGBD (postgreSQL, DB2 , UDB , SQL Server) cette clause FETCH existe depuis longtemps et permet d’afficher le top 10 des résultats d’une requête ou d’en afficher le résultat par tranches de 10 enregistrements pour gérer une espèce de pagination.
Jusqu’alors (avant la version 12c), Oracle permettait d’obtenir un résultat équivalent à cette clause FETCH, mais avec une certaine lourdeur au niveau de l’écriture de la requête SQL, comme je vais tenter de  vous le démontrer dans cet article.
Pour cette démonstration, nous allons d’abord créer une table contenant les nombres de 1 à 100, mais ordonnés de façon décroissante pour bien comprendre certains éléments de syntaxe SQL.

create table nombres ( nombre integer );
declare
  nombre integer := 100;
begin
  loop
    insert into nombres values (nombre) ;
    nombre := nombre - 1;
    exit when nombre = 0;
  end loop;
  commit work;
end;
/

Affichons maintenant les 10 plus petits nombres de cette table.
Pour y parvenir, certains d’entre vous exécuteraient peut-être la requête suivante, sauf que son résultat est faux comme vous pourrez le constater !

SQL> SELECT NOMBRE FROM NOMBRES WHERE ROWNUM <= 10 ORDER BY NOMBRE ;
    NOMBRE
----------
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
10 rows selected.

La pseudo colonne ROWNUM ne fait que ramener les 10 premiers enregistrements de la table puis les ordonner, sauf que les enregistrements de la table ont été insérés par ordre décroissant,
c’est pourquoi le résultat est faux.

Le bon résultat est obtenu par la requête suivante :

SQL> SELECT NOMBRE FROM (SELECT NOMBRE FROM NOMBRES ORDER BY NOMBRE) WHERE ROWNUM <= 10;
    NOMBRE
----------
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
10 rows selected.

Le même résultat correct aurait été obtenu dès la première écriture de la requête et de manière beaucoup plus naturelle, en utilisant la nouvelle clause FETCH comme ceci :

SQL> SELECT NOMBRE FROM NOMBRES ORDER BY 1 FETCH FIRST 10 ROWS ONLY ;

Imaginons maintenant que le résultat attendu soit d’afficher les 5 plus grands nombres parmi les 10 plus petits…c’est déjà un peu plus compliqué, non ?

alors allons y … en utilisant le fameux ROWNUM, cela pourrait donner ceci :

SQL> SELECT NOMBRE FROM (SELECT Q1.NOMBRE , ROWNUM NUMLIG FROM (SELECT NOMBRE FROM NOMBRES ORDER BY 1) Q1 WHERE ROWNUM <= 10) WHERE NUMLIG > 5 ;
    NOMBRE
----------
     6
     7
     8
     9
    10

Pas moins de 3 SELECT imbriqués dans cette requête !!! On se gratte même un peu la tête avant de comprendre ce qu’elle fait , et pourtant cet exemple et la structure de la table utilisée sont extrêmement simples !

Grâce à la nouvelle clause FETCH , voici comment vous auriez pu écrire la même chose :

SQL> SELECT NOMBRE FROM NOMBRES ORDER BY 1 OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY ;

C’est nettement plus facile à coder comme cela , vous ne trouvez pas ?
Alors … qu’attendez vous pour migrer en 12c et remplacer toutes vos requêtes utilisant le ROWNUM par cette nouvelle clause FETCH ?
Vous y gagnerez en lisibilité et donc en exploitation de vos scripts SQL utilisant ce ROWNUM… et en plus, vous serez  portable et pourrez utiliser vos requêtes sur la quasi totalité des autres SGBD !

Vous souhaitez approfondir vos connaissances SQL ? Alors contactez-nous afin de programmer une session sur Paris ou en région