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 :
proc cas;
builtins.defineActionSet /
name="tblMakers"
actions={
{
name="tableCreateParam"
/* Définition des paramètres attendus par l'action */
parms={{name="tblName" type="STRING" required=True}
{name="usernameQ" type="STRING" required=True}}
/* La définition utilise la concaténation pour insérer les variables */
definition=
"fedSQL.execDirect / query='create table casuser.'||strip(tblName)||' {options replace=true} as
select userName, TelNum
from CASUSER.have
where userName='''||strip(usernameQ)||''' ';"
}
};
run;
1
PROC CAS;
2
BUILTINS.defineActionSet /
3
name="tblMakers"
4
actions={
5
{
6
name="tableCreateParam"
7
/* Définition des paramètres attendus par l'action */
/* 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
};
19
RUN;
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é
/* Astuce : gérer la longueur maximale des chaînes citées si nécessaire */
%let _sv_quotelenmax=%sysfunc(getoption(quotelenmax));
options noquotelenmax;
proc cas;
builtins.defineActionSet /
name="tblMakers"
type="CASL"
actions={
{
name="tableCreateParam"
parms={ {name="tblName" type="STRING" required=True}
{name="whereClause" type="STRING" required=False}
}
definition=
"
/* Logique CASL interne : vérifier si le paramètre existe */
if exists('whereClause') then whereClause=catx(' ','where',whereClause);
else whereClause='';
/* Construction et exécution de la requête */
fedSQL.execDirect / query='create table casuser.'||tblName||' {options replace=true} as
select userName, TelNum
from CASUSER.have '||whereClause||' ';
"
}
};
run;
options &_sv_quotelenmax;
1
/* Astuce : gérer la longueur maximale des chaînes citées si nécessaire */
/* 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
};
28
RUN;
29
30
options &_sv_quotelenmax;
Note :
Utilisation
Cette méthode offre une flexibilité totale lors de l'appel de l'action :
proc cas;
/* Appel avec un filtre complexe */
tblMakers.tableCreateParam /
tblName="resultat1"
whereClause="userName='User 1' or TelNum = 333333";
/* Appel sans filtre (crée une copie complète) */
tblMakers.tableCreateParam /
tblName="resultat2";
run;
1
PROC 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";
10
RUN;
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.
Important Disclaimer
The codes and examples provided on WeAreCAS.eu are for educational purposes. It is imperative not to blindly copy-paste them into your production environments. The best approach is to understand the logic before applying it. We strongly recommend testing these scripts in a test environment (Sandbox/Dev). WeAreCAS accepts no responsibility for any impact or data loss on your systems.
SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration. WeAreCAS is an independent community site and is not affiliated with SAS Institute Inc.
This site uses technical and analytical cookies to improve your experience.
Read more.