Accueil du site > Les articles > Techniques de pagination avancées avec SQL DB2
Version à imprimer Enregistrer au format PDF

Techniques de pagination avancées avec SQL DB2

lundi 6 septembre 2010, par Grégory Jarrige Visites  3234

Problématique : Certains SGBD offrent une technique avancée de pagination avec les clauses LIMIT et OFFSET. DB2 n’intègre pas de clauses équivalentes, cet article montre comment pallier ce manque.


Pour gérer la pagination de données avec MySQL, on peut écrire ceci :

select * from t order by id limit  0, 20; -- démarre à 0 et lit 20 lignes

select * from t order by id limit 20, 20; -- lit 20 lignes à partir de la ligne 20

Sur DB2 (dont DB2/400 à partir de la V5R4), on pourra obtenir le même résultat grâce à la clause OVER. Démonstration ci-dessous (avec 2 variantes de la même solution) :

Soit la table ENT_LOG (entités logiques) créée dans la base TSTDATAB avec la structure suivante :

connect to tstdatab;
create table tstdatab.ent_log (
entl_app char(10) not null with default,
entl_id integer not null with default,
entl_nom char (20 ) not null with default,
entl_des char (50 ) not null with default,
) ;
connect reset;

La requête de pagination sera la suivante (affichage des lignes n° 10 à 20) :

- 1ère solution : sans la clause WITH

select * from (  
 select entl_id, entl_nom, entl_des,  
         row_number() over (order by entl_nom asc) as rn  
 from tstdatab.ent_log
) as foo  
where rn between 10 and 20 ;

- 2ème solution : avec utilisation de la clause WITH

with devshedtest as
( select entl_id, entl_nom, entl_des,  
        row_number() over (order by entl_nom asc) as rn
 from tstdatab.ent_log )
select entl_id, entl_nom, entl_des, rn
 from devshedtest
 where rn between 10 and 20 ;

J’ai testé ces 2 techniques avec une table contenant environ 3500 lignes. Elles donnent le même résultat avec des temps d’exécution identiques (inférieur à la seconde sur DB2 en version 9 sous Windows).

Piège à éviter : sur DB2/400 en V5R3, la clause OVER ne fonctionnant pas, on pourrait être tenté de gérer la pagination via la technique suivante (qui ne fonctionne pas) :

select * from
(
        select a.*, rrn(a) as rn from lstpays a            
) as foo                  
where rn between 1 and 10
order by codfra          

En effet, cette technique ne peut pas fonctionner, car la fonction RRN() renvoie le numéro relatif de ligne, qui ne correspond en aucun cas au numéro de la ligne à l’intérieur du « result set » obtenu.

La solution à ce problème, que j’ai trouvée sur un forum dédié à DB2 pour Z/OS, est la suivante :

select *
from lstpays a,  
    table (
                select count(*) as rownum  
from lstpays as b
where a.codfra >= b.codfra
        ) temp_tab                        
Where rownum between 11 and 20    
order by rownum, codfra            
fetch first 10 rows only