Programmation SAS Avancée : Booster vos Macros grâce aux fonctions I/O et %SYSFUNC

Dans nos précédents articles, nous avons exploré comment les fonctions d'Entrées/Sorties (I/O) à bas niveau permettaient d'analyser des tables SAS et de lire des fichiers textes complexes depuis une étape DATA.

Mais que faire si vous avez besoin de vérifier le contenu d'un fichier de paramétrage avant même de générer votre code ? Ou si vous souhaitez créer une macro utilitaire capable de vérifier l'état d'une table sans exécuter de procédure coûteuse en ressources ?

La solution réside dans l'alliance des fonctions I/O et du langage Macro, principalement via la fonction %SYSFUNC. Aujourd'hui, nous allons voir comment donner des "yeux" à vos macros.


1. La passerelle %SYSFUNC : Les I/O en mode Macro

Le langage Macro de SAS ne possède pas de fonctions I/O qui lui sont propres. Pour contourner cela, nous utilisons %SYSFUNC, qui agit comme une passerelle permettant d'exécuter la quasi-totalité des fonctions de l'étape DATA directement dans l'environnement macro.


Il y a cependant quelques différences fondamentales à garder à l'esprit :


  1. Tout est texte : Il n'y a pas de variablesColonnes d'une table SAS contenant des données spécifiques (numériques ou caractères). Elles possèdent des attributs comme le nom, le type, la longueur, l'étiquette et le format d'affichage. numériques en langage Macro. Tous les identifiants (comme le File ID) ou les codes de retour sont convertis en texte.

  2. Pas de guillemets : L'environnement macro n'utilise pas les guillemets de la même manière. Si une fonction demande un texte constant, vous l'écrivez directement sans l'entourer de guillemets.


  3. Fermeture obligatoire : Une étape DATA ferme automatiquement les fichiers à la fin de son exécution. En macro, si vous oubliez de fermer un fichier avec CLOSE, il restera verrouillé jusqu'à la fermeture de votre sessionInstance de connexion active entre un client et le serveur CAS (Cloud Analytic Services), isolant les ressources, les bibliothèques et les traitements d'un utilisateur au sein de SAS Viya. SAS.

2. Cas pratique : Récupérer les métadonnéesInformations décrivant les données, les utilisateurs et les ressources dans SAS Viya. Elles assurent la traçabilité, la sécurité et la gouvernance au sein de l'architecture distribuée. d'une table à la volée

Souvent, on a besoin de savoir combien de lignes contient une table avant de lancer un traitement. Au lieu de faire une étape PROC SQL (qui génère de l'I/O inutile), nous pouvons le faire de manière instantanée avec les fonctions OPEN et ATTRN via %SYSFUNC.


Voici une macro générique qui réalise cette action :

SAS


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
%macro obtenir_nb_lignes(nom_table);
/* 1. Ouverture de la table en mode lecture séquentielle ('IS') */
/* Notez l'absence de guillemets autour de IS */
%let id_table = %sysfunc(open(&nom_table, IS));

/* 2. Vérification que la table est bien ouverte */
%if &id_table > 0 %then %do;

/* 3. Récupération de l'attribut NLOBS (Number of Logical Observations) */
%let nb_lignes = %sysfunc(attrn(&id_table, NLOBS));

%put NOTE: La table &nom_table contient &nb_lignes lignes.;

/* 4. Fermeture OBLIGATOIRE de la table */
%let code_fermeture = %sysfunc(close(&id_table));
%end;
%else %do;
%put ERREUR: Impossible d'ouvrir la table &nom_table..;
%end;
%mend;

/* Appel de la macro */
%obtenir_nb_lignes(WORK.MES_DONNEES);

Pourquoi c'est puissant ? Cette macro s'exécute en une fraction de seconde, sans compiler aucune étape DATA. L'identifiant &id_table et le code de retour de fermeture &code_fermeture sont stockés silencieusement.


3. L'appel de routines avec %SYSCALL

Si %SYSFUNC gère les fonctions (qui renvoient une valeur), comment gérer les routines (qui exécutent une action sans renvoyer de valeur, comme CALL SET) ?

SAS propose l'instruction %SYSCALL. La grande particularité de %SYSCALL est que ses arguments doivent être des noms de variablesColonnes d'une table SAS contenant des données spécifiques (numériques ou caractères). Elles possèdent des attributs comme le nom, le type, la longueur, l'étiquette et le format d'affichage. macros, et non leurs valeurs (pas de &).


Par exemple, si vous souhaitez utiliser la routine SET pour lier automatiquement le buffer de données (DDV), vous écrirez :


SAS


1
2
3
%let id_table = %sysfunc(open(WORK.PARAMETRES, IS));
/* Attention, pas de & devant id_table dans un %SYSCALL ! */
%syscall set(id_table);

4. Rendre le code portable avec la macro %SYSRC

Dans nos exemples d'étape DATA, nous testions souvent si le code de retour de FETCH était égal à 0 (succès) ou -1 (fin du fichier). Le problème est que ces codes numériques peuvent parfois varier selon le système d'exploitation.


En programmation Macro, SAS fournit une macro utilitaire très élégante : %SYSRC. Elle permet d'utiliser des mnémoniques standards plutôt que des chiffres absolus.


Voici quelques codes mnémoniques utiles :


  • %sysrc(_SOK) : Succès (généralement 0)
  • %sysrc(_SWEOF) : End of File (Fin de fichier)
  • %sysrc(_SELOCK) : Le fichier est verrouillé par un autre processus
  • %sysrc(_SWNOFLE) : Le fichier n'existe pas

5. Exemple Complet : Lire des paramètres dynamiquement

Imaginons une table WORK.CONFIG contenant deux colonnes : PARAM_NOM et PARAM_VALEUR. Nous voulons lire cette table ligne par ligne directement en Macro, et créer une variable macro globale pour chaque paramètre lu.


SAS


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
%macro charger_parametres(table_config);

/* 1. Ouverture de la table */
%let id_table = %sysfunc(open(&table_config, IS));

%if &id_table = 0 %then %do;
%put ERREUR: Table de configuration &table_config introuvable.;
%return; /* On quitte la macro prématurément */
%end;

/* 2. Récupération du numéro (index) des colonnes */
%let num_col_nom = %sysfunc(varnum(&id_table, PARAM_NOM));
%let num_col_val = %sysfunc(varnum(&id_table, PARAM_VALEUR));

%if &num_col_nom = 0 or &num_col_val = 0 %then %do;
%put ERREUR: Les colonnes PARAM_NOM et PARAM_VALEUR sont requises.;
%let rc = %sysfunc(close(&id_table));
%return;
%end;

/* 3. Boucle de lecture avec gestion du End Of File (EOF) */
/* On initialise le code de lecture à 0 (_SOK) */
%let code_lecture = %sysrc(_SOK);

%do %while(&code_lecture = %sysrc(_SOK));

/* On charge la ligne suivante */
%let code_lecture = %sysfunc(fetch(&id_table));

/* Si on a lu une ligne avec succès */
%if &code_lecture = %sysrc(_SOK) %then %do;

/* On extrait les données en texte (GETVARC) */
%let nom_macro_var = %sysfunc(getvarc(&id_table, &num_col_nom));
%let valeur_macro_var = %sysfunc(getvarc(&id_table, &num_col_val));

/* On crée la variable macro globale dynamiquement */
%global &nom_macro_var;
%let &nom_macro_var = &valeur_macro_var;

%put NOTE: Paramètre chargé -> &nom_macro_var = &valeur_macro_var;
%end;
%end;

/* 4. Vérification si on s'est bien arrêté à cause de la fin du fichier */
%if &code_lecture ne %sysrc(_SWEOF) %then %do;
%put ATTENTION: La lecture s'est arrêtée suite à une erreur inattendue.;
%end;

/* 5. Fermeture de la table */
%let rc = %sysfunc(close(&id_table));

%mend;

/* Exécution de notre outil de chargement */
%charger_parametres(WORK.CONFIG);

Conclusion

Intégrer les I/O de bas niveau dans vos macros avec %SYSFUNC ouvre un monde de possibilités. Vous n'êtes plus limité à générer du code statique : vos macros peuvent désormais interroger l'environnement, lire des tables ou des fichiers plats de manière autonome, et prendre des décisions avant même que l'analyse des données ne commence.


Dans notre 5ème et dernier article de cette série, nous aborderons une astuce qui fait toujours son petit effet : comment utiliser ces mêmes concepts I/O pour envoyer des e-mails automatisés (avec des statuts de traitement par exemple) directement depuis vos programmes SAS !

Nicolas Housset

Passionné d'informatique, je suis Consultant et expert technique SAS VIYA, également co-fondateur de la société Flexcelite. Spécialisé dans les technologies SAS (Viya, 9.4) et les infrastructures associées (Linux, Hadoop, Azure), ce blog est mon espace pour partager mes mémos techniques et retours d'expérience.