Sélectionner l’enregistrement max en une seule fois – la clause magique keep

Une problématique récurrente dans les traitements décisionnels est de récupérer le dernier enregistrement d’une série, par exemple les dernières opérations des clients en ayant en source une table contenant toutes les opérations.

Avoir uniquement la dernière date d’opération est simple, rapide et à portée de tous:

/* exemple **
with operations
as (  
select 1 idclient, sysdate dat, 4 val from dual union all
select 1 idclient, sysdate+1 dat, 8 val from dual union all
select 1 idclient, sysdate+2 dat, 7 val from dual union all
select 2 idclient, sysdate dat, 2 val from dual ) */
select idclient, max(dat) from operations group by idclient

Par contre si on veut récupérer d’autres informations de cet enregistrement, il faut passer par une sous-requête :

select idclient,  dat,  val
from operations a
where a.dat=(select max(b.dat) from operations b where b.idclient=a.idclient )

Le problème est ( entre autres ) qu’on passe 2 fois sur la table operations, ce qui dégrade les performances.

Oracle propose depuis la 9i les fonctions analytiques, ce qui est bien pratique pour gérer ce type de problème.
On utilisera par exemple la fonction row_number(), mais on aura toujours une sous-requête :

select idclient, dat, val from (
  select idclient, dat, val,
    row_number() over(partition by idclient order by dat desc) num
  from operations
)
where num=1

Cette solution n’est pas forcément simple à implémenter du fait de la sous-requête. Un ETL comme Sunopsis/ODI ne gère pas les sous-requêtes, il faut passer par des vues et du coup on perdra le lien dans l’analyse d’impact de l’outil.
Solution miracle, on a une requête en one-shot avec la clause keep :

select idclient,
  max(dat),
  max(val) keep (dense_rank last  order by dat) val
from operations
group by idclient

Cerise sur le gâteau, on peut aussi utiliser ce type de clause dans un univers Business Objects, cela évite de passer par une table dérivée ou du sql en dur.

Que du bonheur.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>