macro SAS9

Exécuter des rapports conditionnels et éviter les pièges des macros

Simon 24 vistas
Nivel de dificultad
Débutant
Publicado el :
Stéphanie

Consejo del experto

Stéphanie

L'automatisation robuste ne s'improvise pas : interroger la variable &SQLOBS après une vue est une erreur classique qui peut fausser toute votre chaîne de production. Adoptez le réflexe "Métadonnées" : interroger les tables dictionnaires (sashelp.vtable) est la seule méthode qui garantit un résultat instantané sans jamais lire les données, une économie de ressources cruciale sur les gros volumes.

L'automatisation est au cœur de la programmation SAS©. Un scénario classique consiste à vérifier le contenu d'une table avant de lancer un traitement : "Si ma table contient des données, lance le rapport standard, sinon lance un rapport d'anomalie."

Bien que la logique semble simple, sa mise en œuvre via le langage macro peut se heurter à deux obstacles majeurs : la portée des variables et le comportement trompeur de certaines variables automatiques comme SQLOBS.

Le Problème : Pourquoi mon code ne voit-il pas l'erreur ?

Imaginons un code structuré en deux macros :

  1. %Check_Data : Vérifie les données et crée un indicateur &error.

  2. %Run_Report : Lit &error et décide quel rapport imprimer.

L'erreur fréquente est de définir la variable &error à l'intérieur de la première macro sans précaution.

1. Le piège de la portée (Scope) Par défaut, une macro-variable créée à l'intérieur d'une macro (via %LET) est locale. Elle n'existe que le temps de l'exécution de cette macro. Dès que %Check_Data se termine, la variable &error est détruite. Lorsque %Run_Report tente de lire &error, elle ne trouve rien, et le programme plante (erreur "Apparent symbolic reference not resolved").

La Solution : Il faut déclarer la variable comme globale au début du programme ou avant son utilisation :

1%GLOBAL error;
2%LET error = 0;

Le Piège Technique : SQLOBS et les Vues

Une autre erreur subtile concerne la méthode de comptage. Le développeur tentait ici de détecter si une table était vide en vérifiant la variable automatique &SQLOBS juste après une instruction CREATE VIEW.

1PROC SQL;
2 CREATE VIEW work.ma_vue AS SELECT * FROM SOURCE;
3QUIT;
4/* Le développeur pense que &SQLOBS contient le nombre de lignes... */

C'est une erreur logique. La création d'une vue ne lit pas les données, elle ne fait que définir une structure. Par conséquent, SAS© renvoie toujours SQLOBS = 0 après la création d'une vue, même si la table sous-jacente contient des millions de lignes. Le rapport d'erreur se déclenchait donc systématiquement à tort.

La Bonne Pratique

Pour conditionner l'exécution de vos rapports (procédure PRINT, REPORT, etc.), voici la marche à suivre :

  1. Ne pas encapsuler vos appels de macros contenant des procédures (Proc Print, etc.) à l'intérieur d'une étape DATA _NULL_. Les macros s'appellent directement en code ouvert.

  2. Compter les lignes correctement : Pour vérifier si une table est vide sans la lire entièrement (ce qui est coûteux en ressources), interrogez les métadonnées via les dictionnaires SAS©.

Voici un exemple robuste :

1/* 1. Récupérer le nombre d'observations depuis les métadonnées */
2PROC SQL NOPRINT;
3 SELECT (nobs - delobs) INTO :num_obs
4 FROM dictionary.tables
5 WHERE LIBNAME = 'WORK' AND memname = 'MA_TABLE';
6QUIT;
7 
8/* 2. Logique conditionnelle */
9%MACRO Choisir_Rapport;
10 %IF &num_obs > 0 %THEN %DO;
11 %Put --- Lancement du Rapport Standard ---;
12 /* %Rapport_Standard; */
13 %END;
14 %ELSE %DO;
15 %Put --- TABLE vide : Lancement du Rapport d'Erreur ---;
16 /* %Rapport_Erreur; */
17 %END;
18%MEND;
19 
20%Choisir_Rapport;
Cette méthode est à la fois plus performante (pas de lecture de données inutile) et plus fiable pour gérer vos flux de production.