DBAdapter et liste de paramètres

Dans un précédent article nous faisions un tour d’horizon sur le DBAdapter, et notamment de ses limites. Certaines d’entre elles sont difficilement contournables, mais voici une astuce qui vous permettra de fournir une « liste » de paramètres !

Besoin

Vous souhaitez pouvoir utiliser le DBAdapter pour effectuer une recherche afin de récupérer une liste d’éléments, avec un champ pouvant prendre plusieurs valeurs différentes.
Cette sélection correspondrait par exemple à une requête du type :

Select * from CLIENT where NOM IN (‘DUPONT’,’DOE’) ;

Problème

Actuellement il semblerait qu’il soit impossible de déterminer un paramètre sous la forme d’une liste. Cependant, en respectant les limites connues, il doit être possible de contourner ce problème.

Recherche de solutions

1ère approche

La première idée consiste à fournir un paramètre qui contiendrait « ‘DUPONT’,’DOE’ ». Cependant on se rend compte rapidement (et logiquement) que ce paramètre sera inclus dans sa totalité comme un seul élément, qui donnerait en fait quelque chose proche de :

Select * from CLIENT where NOM IN (#listeParametre) ;
=>
Select * from CLIENT where NOM IN (« ‘DUPONT’,’DOE’ ») ;

En effet, le résultat n’est pas celui escompté, celui-ci ne renvoyant que les clients ayant pour nom « ‘DUPONT,’DOE’ » et non « DUPONT » et « DOE ».

2ème approche

La seconde idée qui peut venir à l’esprit est de finalement fournir un nombre d’éléments finis en paramètres, et se débrouiller pour compléter si nécessaire avec des valeurs ne pouvant exister

Select * from CLIENT where NOM IN (#param1,#param2,#param3,#param4) ;
=>
Select * from CLIENT where NOM IN (‘DUPONT’,’DOE’,’-1’,’-1’) ;

Ici, on se rapproche du résultat voulu. On pourra reprocher 2 choses principalement :

  • Un nombre maximum de paramètres à fournir fixe
  • Une valeur « pour compléter » qui doit de manière certaine ne jamais exister, pour ne pas risquer de renvoyer des résultats non voulus.

3ème approche : la meilleure solution ?

La dernière solution consiste à utiliser des fonctions de la base de données dans la requête afin de permettre l’interprétation d’un paramètre qui contiendrait l’ensemble des valeurs que l’on souhaite voir prises en compte.
Voici l’extrait SQL qui va permettre de transformer une chaine du type ‘DUPONT:DOE’ en liste de paramètres à fournir dans le IN de la requête :

SELECT SUBSTR (DELIMITED_INPUT_STRING, DECODE(LEVEL, 1, 1,
INSTR(DELIMITED_INPUT_STRING, DELIMITER, 1, LEVEL-1)+1),
INSTR(DELIMITED_INPUT_STRING, DELIMITER, 1, LEVEL) -
DECODE(LEVEL, 1, 1, INSTR(DELIMITED_INPUT_STRING,
DELIMITER, 1, LEVEL-1)+1) ) FROM (SELECT #listeParametre ||
':' AS DELIMITED_INPUT_STRING , ':' AS DELIMITER FROM DUAL)
CONNECT BY INSTR(DELIMITED_INPUT_STRING, DELIMITER, 1, LEVEL)>0

Je ne détaillerai pas ici le rôle de chacune des fonctions utilisées, mais vous invite à vous renseigner sur chacune d’elles pour comprendre le fonctionnement de cette requête.
Cette requête donne en exécutant avec ‘DUPONT:DOE:JOHN:EASYTEAM’ :

  • DUPONT
  • DOE
  • JOHN
  • EASYTEAM

Finalement, on va donner au IN le résultat de ce select qui a pour rôle de découper au niveau des « : » la chaine de caractère fournie (à la place de #listeParametre). A noter que dans cette requête les « : » sont positionnés en dur, mais qu’ils peuvent être également mis en paramètre si nécessaire.
Notre requête finale ressemblera à ceci :

Select * from CLIENT where NOM IN
(SELECT SUBSTR (DELIMITED_INPUT_STRING, DECODE(LEVEL, 1, 1,
INSTR(DELIMITED_INPUT_STRING, DELIMITER, 1, LEVEL-1)+1)
, INSTR(DELIMITED_INPUT_STRING, DELIMITER, 1, LEVEL) -
DECODE(LEVEL, 1, 1, INSTR(DELIMITED_INPUT_STRING, DELIMITER,
1, LEVEL-1)+1) ) FROM (SELECT #listeParametre || ':' AS
DELIMITED_INPUT_STRING , ':' AS DELIMITER FROM DUAL)
CONNECT BY INSTR(DELIMITED_INPUT_STRING, DELIMITER, 1, LEVEL)>0) ;

Conclusion

Le DBAdapter est très utile pour permettre des échanges avec la base de données, mais reste tout de même limité dans ses capacités. Certaines astuces peuvent être justifiées (comme celle-ci à mon sens) car elles permettent de réaliser des actions « simples » mais non fournies par l’adapter en l’état.
Cette astuce permet également d’ouvrir la voie peut être à d’autres astuces, mettant en avant une partie rarement utilisée par les développeurs (ou pas intuitivement) : utiliser les capacités de la base pour aider à pallier à un manque.
Sources