CAS

Passer des paramètres dynamiques à FedSQL dans une Action Personnalisée

Simon 24/05/2023 9 vues

La création d'actions définies par l'utilisateur (User-Defined Actions) dans SAS© Viya permet d'encapsuler une logique complexe pour la rendre réutilisable. Cependant, un défi technique survient souvent lorsque l'on tente d'imbriquer du code FedSQL à l'intérieur de ces définitions : la gestion des guillemets (quoting) lors du passage de paramètres (comme des chaînes de caractères) dans la requête SQL.

Cet article explore les méthodes pour résoudre ce problème, allant de la simple concaténation à la construction dynamique de clauses WHERE.

Le Problème : La "Soupe" de Guillemets

L'objectif est simple : créer une action CAS qui prend un nom d'utilisateur en paramètre et crée une table filtrée sur ce nom via fedSQL.execDirect.

Le défi réside dans la syntaxe. La définition de l'action est elle-même une chaîne de caractères (souvent entre guillemets doubles). La requête FedSQL est une chaîne à l'intérieur de cette définition (souvent entre guillemets simples). Enfin, la valeur littérale dans le SQL (le nom d'utilisateur) doit être entourée de guillemets simples.

Une tentative naïve échoue souvent car le paramètre n'est pas résolu correctement à l'intérieur de la chaîne littérale de la requête.

Solution 1 : La Concaténation Propre

La méthode la plus robuste pour insérer une variable CASL (le paramètre de votre action) dans la chaîne de requête FedSQL est d'utiliser l'opérateur de concaténation (||) à l'intérieur de la définition.

Il faut "sortir" de la chaîne SQL, concaténer la variable, puis "rentrer" dans la chaîne, tout en s'assurant que les guillemets simples nécessaires au SQL (') sont bien présents.

Exemple de code

Voici comment définir l'action pour qu'elle accepte un paramètre usernameQ et l'insère proprement :

Illustration
1PROC CAS;
2 BUILTINS.defineActionSet /
3 name="tblMakers"
4 actions={
5 {
6 name="tableCreateParam"
7 /* Définition des paramètres attendus par l'action */
8 parms={{name="tblName" type="STRING" required=True}
9 {name="usernameQ" type="STRING" required=True}}
10
11 /* La définition utilise la concaténation pour insérer les variables */
12 definition=
13 "fedSQL.execDirect / query='create TABLE casuser.'||strip(tblName)||' {options replace=true} as
14 select userName, TelNum
15 from CASUSER.have
16 where userName='''||strip(usernameQ)||''' ';"
17 }
18 };
19RUN;
Notez la syntaxe du WHERE : '''||strip(usernameQ)||'''.

Le premier ' ferme la chaîne de la requête SQL.

Les deux ' suivants ('') sont une manière d'échapper un guillemet simple pour qu'il soit interprété comme un littéral par CASL, ce qui résultera en un guillemet ouvrant pour le SQL.

Ensuite vient la variable.

Et enfin la fermeture symétrique.

Solution 2 : Logique Dynamique et Clause WHERE Optionnelle

Une approche plus avancée consiste à utiliser la puissance du langage CASL à l'intérieur de la définition de l'action (definition=...). Puisque la définition contient du code CASL exécutable, vous pouvez utiliser des conditions IF/ELSE pour construire votre requête SQL dynamiquement avant de l'exécuter.

Cela permet, par exemple, de passer une clause WHERE complète ou de la laisser vide.

Exemple de code avancé

1/* Astuce : gérer la longueur maximale des chaînes citées si nécessaire */
2%let _sv_quotelenmax=%sysfunc(getoption(quotelenmax));
3options noquotelenmax;
4 
5PROC CAS;
6 BUILTINS.defineActionSet /
7 name="tblMakers"
8 type="CASL"
9 actions={
10 {
11 name="tableCreateParam"
12 parms={ {name="tblName" type="STRING" required=True}
13 {name="whereClause" type="STRING" required=False}
14 }
15 definition=
16 "
17 /* Logique CASL interne : vérifier si le paramètre existe */
18 if exists('whereClause') then whereClause=catx(' ','where',whereClause);
19 else whereClause='';
20
21 /* Construction et exécution de la requête */
22 fedSQL.execDirect / query='create TABLE casuser.'||tblName||' {options replace=true} as
23 select userName, TelNum
24 from CASUSER.have '||whereClause||' ';
25 "
26 }
27 };
28RUN;
29 
30options &_sv_quotelenmax;
Note :
Utilisation
Cette méthode offre une flexibilité totale lors de l'appel de l'action :
1PROC CAS;
2 /* Appel avec un filtre complexe */
3 tblMakers.tableCreateParam /
4 tblName="resultat1"
5 whereClause="userName='User 1' or TelNum = 333333";
6
7 /* Appel sans filtre (crée une copie complète) */
8 tblMakers.tableCreateParam /
9 tblName="resultat2";
10RUN;

L'intégration de FedSQL dans les actions définies par l'utilisateur ne nécessite pas de manipulations de chaînes illisibles. En utilisant l'opérateur de concaténation || et en tirant parti de la capacité du paramètre definition à exécuter de la logique CASL (comme if exists), vous pouvez créer des actions robustes, lisibles et hautement paramétrables.