Construire des macros variables avec une PROC SQL
Il y a plusieurs façons de créer des macros variables dans un programme SAS.
Il y a l'instruction %LET, la routine CALL SYMPUT dans une étape DATA et l'utilisation de la PROC SQL avec la clause INTO :.
L'idée de cette instruction est de mettre le résultat d'un SELECT de la PROC SQL dans une ou plusieurs macro(s). La transformation d'un "résultat" à la création de macros variables se fait avec l'utilisation de la clause INTO : avant le FROM de la requête.
Exemple 1 : D'une requête SQL à la création d'une macro.
Prenons une requête simple:
PROC SQL;
SELECT MAX(CrHits) FROM sashelp.baseball
;
QUIT;
/*Résultat: 4256*/
Si vous voulez passer la variable qui résulte de cette requête (16) dans une macro variable vous allez devoir utiliser l'instruction INTO :
PROC SQL;
SELECT MAX(CrHits) INTO :resultat_max FROM sashelp.baseball
;
QUIT;
/* Maintenant la macro &resultat_max a une valeur (4256) */
/* On l'affiche dans la log */
%PUT &resultat_max;
C'est le résulat de la PROC SQL qui donnera la valeur de votre macro variable. Vous pouvez donc utiliser, les group by, order by, where, having...
PROC SQL;
SELECT MAX(CrHits) INTO :resulat_max_EAST FROM sashelp.baseball
WHERE Division = "East"
;
QUIT;
%PUT &resulat_max_EAST; /* 2464 */
Si le resulat de votre select renvoie plus d'une ligne, c'est la première qui sera assignée à la macro variable
Vous pouvez tout à fait composer votre requête de manière à créer plusieurs macros variables ayant plusieurs résultat dans votre instruction SELECT:
PROC SQL;
SELECT MAX(CrHits), MIN(CrHits) INTO :resulat_max_EAST, :resulat_min_EAST FROM sashelp.baseball
WHERE Division = "East"
;
QUIT;
%PUT &resulat_max_EAST; /*2464*/
%PUT &resulat_min_EAST; /*34*/
Exemple 2 : D'une requête SQL à la création d'une macro variable composée.
Au delà de créer une macro variable (ce qui est déjà bien) la PROC SQL avec la clause INTO : prend tout son sens selon moi lorsque l'on veut construire une macro variable composée.
Au lieu d'avoir une valeur 'sèche' qui correspond à la première ligne de votre SELECT vous allez pouvoir la composer des plusieurs lignes. Pour cela on doit positionner un séparateur entre les différente valeurs résultat de la requête. On le fait avec "SEPARATED BY".
Exemple avec une requête sur la liste des noms de la table class:
PROC SQL;
SELECT DISTINCT Team FROM sashelp.baseball
;
QUIT;
/*
Team
Atlanta
Baltimore
Boston
.
.
.
*/
Si nous voulons créer une macro variable avec la liste de ces noms nous devons utiliser la syntaxe suivante:
PROC SQL;
SELECT DISTINCT Team INTO :liste_teams SEPARATED BY " " FROM sashelp.baseball
;
QUIT;
%PUT &liste_teams;
/* LOG:
Atlanta Baltimore Boston California Chicago Cincinnati Cleveland Detroit Houston Kansas City Los Angeles Milwaukee Minneapolis
Montreal New York Oakland Philadelphia Pittsburgh San Diego San Francisco Seattle St Louis Texas Toronto
*/
Vous pouvez bien entendu jouer avec le paramètre SEPARATED BY et l'utiliser comme bon vous semble.
PROC SQL;
/* Séparateur simple */
SELECT DISTINCT Team INTO :liste_teams SEPARATED BY " , " FROM sashelp.baseball;
/* Séparateur avec quote sur les noms de teams */
SELECT DISTINCT quote(trim(Team)) INTO :liste_teams2 SEPARATED BY " , " FROM sashelp.baseball WHERE Team like 'C%';
QUIT;
%PUT &liste_teams;
/* Atlanta , Baltimore , Boston , California , Chicago , Cincinnati , Cleveland.... */
%PUT &liste_teams2;
/* "California" , "Chicago" , "Cincinnati" , "Cleveland" */
Vous pouvez ainsi réutiliser ces macros variables dans d'autres PROC ou étapes DATA. La macro variable &liste_teams2 peut par exemple directement être utilisée dans un IN.
options mprint; /* Permet d'afficher la valeur des macro dans la log au moment de l'exécution */
DATA EX_BASEBALL; SET SASHELP.BASEBALL;
WHERE TEAM IN (&liste_teams2);
RUN;
/* LOG
NOTE: There were 61 observations read from the data set SASHELP.BASEBALL.
WHERE TEAM in ('California', 'Chicago', 'Cincinnati', 'Cleveland');
NOTE: The data set WORK.EX_BASEBALL has 61 observations and 24 variables.
*/
En définitive la création de macros variables avec l'instruction INTO dans une PROC SQL permet de rendre votre code beaucoup plus flexible et de généraliser des procédure.
Quelques utilisations possibles:
- Aller récupérer une liste de variables à utiliser dans une PROC CORR depuis la table DICTIONARY.COLUMNS
- Mettre à jour des tables en fonction de paramètres mouvants venant d'une autre table
- Générer des conditions WHERE dynamiques
Petits tips:
- Vous pouvez ajouter l'option NOPRINT dans la procédure PROC SQL pour ne pas avoir l'output du SELECT
- L'utilisation du INTO n'est pas compatible avec la création de table. Seul le SELECT peut être utiliser
- Les valeurs des macrovariables sont directement assignée pendant la PROC SQL donc directement mobilisables dans le reste de la procédure.
- Le nombre de INTO doit correspondre au nombre de variables résultat de votre SELECT
Références et documentation
- SQL Procedure INTO CLAUSE https://documentation.sas.com/?docsetId=sqlproc&docsetTarget=n1tupenuhmu1j0n19d3curl9igt4.htm&docsetVersion=9.4&locale=en
- CREATING MACRO VARIABLES VIA PROC SQL: https://stats.idre.ucla.edu/wp-content/uploads/2016/02/cc107.pdf
- 3 méthodes pour construire des macros variables sans macro: https://thesasreference.wordpress.com/2008/02/07/creer_macro_variable/
- SAS Introduction au décisionnel: du data management au reporting (3èm ED) page 488+ https://www.amazon.fr/SAS-Introduction-d%C3%A9cisionnel-management-reporting/dp/221267631X