Dans un précédent article, nous avons vu pourquoi les fonctions d'entrées/sorties (I/O) à bas niveau de SAS, comme OPEN et FETCH, offraient une flexibilité inégalée par rapport aux instructions classiques comme SET.
Aujourd'hui, nous allons nous attaquer à un cas d'usage concret et particulièrement complexe à résoudre avec la programmation traditionnelle : comment lire et traiter une table SAS (Data Set) sans connaître à l'avance le nom de ses colonnes, ni même son nombre 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. ?
Si vous développez des macros génériques censées s'adapter à n'importe quel fichier en entrée, cette technique est tout simplement indispensable.
1. La limite de l'approche classique
Habituellement, dans une étape DATA, vous devez connaître le nom des 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. que vous manipulez. Si vous souhaitez récupérer la valeur d'une colonne pour faire un calcul, vous devez l'appeler explicitement.
Mais que faire si vous construisez un outil de profilage de données, ou une macro d'export dynamique ? Vous ne pouvez pas coder les noms des colonnes en dur. C'est ici que les fonctions I/O de bas niveau entrent en jeu, en nous permettant de "scanner" la structure de la table à la volée.
2. L'arsenal des fonctions de découverte (Les fonctions "VAR")
Pour explorer une table inconnue, la stratégie consiste à procéder par étapes, exactement comme le ferait un détective. SAS met à notre disposition un ensemble de fonctions prévues à cet effet :
ATTRN(Attribute Numeric) : Utilisée avec l'argument'NVARS', cette fonction nous donne la clé de voûte de notre exploration : le nombre total 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. (colonnes) présentes dans la table. SAS numérote ces 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. de 1 jusqu'à ce nombre.VARNAME: En lui passant l'identifiant de la table et un numéro d'indexStructure de données accélérant la lecture des lignes d'une table en ciblant directement les valeurs des colonnes indexées, réduisant ainsi les entrées/sorties disque et le temps de traitement. (de 1 au nombre total 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.), elle nous renvoie le nom exact de la colonne.VARTYPE: Avec les mêmes arguments, elle nous indique le type de la donnée :'C'pour Caractère (texte) et'N'pour Numérique. C'est crucial pour savoir comment lire la valeur ensuite.GETVARCetGETVARN: Une fois la ligne chargée en mémoireGemini said
Espace de stockage temporaire (RAM) utilisé par le moteur CAS pour charger et traiter les données à haute vitesse, minimisant les accès disque pour optimiser les performances de SAS Viya. (grâce àFETCH), ces fonctions extraient la valeur de la colonne en fonction de son type.
3. Exemple Pratique : Le Scanner Dynamique
Imaginons que nous recevons une table nommée WORK.MA_TABLE_INCONNUE. Nous allons écrire un programme qui va l'ouvrir, compter ses colonnes, identifier chaque type, et imprimer dynamiquement dans la log le contenu de la toute première ligne.
Voici le code détaillé :
SAS
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
/* 1. Déclaration de nos variables de travail (PDV) */
length nom_colonne $ 32
type_colonne $ 1
valeur_texte $ 200;
/* 2. Ouverture de la table en mode lecture ('I' pour Input) */
id_table = open('WORK.MA_TABLE_INCONNUE', 'I');
if id_table = 0 then do;
putlog "ERREUR CRITIQUE: Impossible d'ouvrir la table.";
stop;
end;
/* 3. Combien y a-t-il de colonnes dans cette table ? */
nb_variables = attrn(id_table, 'NVARS');
putlog "ÉTAPE 1 : La table contient " nb_variables " colonnes.";
/* 4. Chargement de la première observation (ligne) en mémoire (dans le DDV) */
code_retour = fetch(id_table);
if code_retour ne 0 then do;
putlog "ATTENTION: La table est vide ou un problème est survenu.";
goto fin_programme;
end;
putlog "ÉTAPE 2 : Découverte et lecture de la première ligne...";
putlog "---------------------------------------------------";
/* 5. La boucle magique : on itère sur chaque index de colonne */
do index_col = 1 to nb_variables;
/* Découverte du nom et du type pour cet index */
nom_colonne = varname(id_table, index_col);
type_colonne = vartype(id_table, index_col);
/* 6. Extraction de la donnée selon son type */
if type_colonne = 'C' then do;
/* C'est du texte, on utilise GETVARC */
valeur_texte = getvarc(id_table, index_col);
putlog "- Colonne N°" index_col " | Nom: " nom_colonne " | Type: Texte | Valeur: " valeur_texte;
end;
else if type_colonne = 'N' then do;
/* C'est un nombre, on utilise GETVARN */
valeur_num = getvarn(id_table, index_col);
putlog "- Colonne N°" index_col " | Nom: " nom_colonne " | Type: Numérique | Valeur: " valeur_num;
end;
end;
putlog "---------------------------------------------------";
/* 7. Propreté avant tout : fermeture de la table */
fin_programme:
code_retour = close(id_table);
run;
Décryptage de l'exemple :
- L'agnosticisme du code : Remarquez que nulle part dans ce code nous n'avons écrit de nom de colonne spécifique (comme
AGEouVILLE). Ce programme fonctionnera de la même manière sur une table de 3 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. que sur une table de 500 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.. - L'indexation relative : La force de ce script réside dans la boucle
do index_col = 1 to nb_variables;. En SAS, les 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. stockées dans le buffer mémoireGemini said
Espace de stockage temporaire (RAM) utilisé par le moteur CAS pour charger et traiter les données à haute vitesse, minimisant les accès disque pour optimiser les performances de SAS Viya. (le DDV) sont numérotées séquentiellement. Les fonctionsVARNAME,VARTYPE,GETVARCetGETVARNs'appuient toutes sur cet indexStructure de données accélérant la lecture des lignes d'une table en ciblant directement les valeurs des colonnes indexées, réduisant ainsi les entrées/sorties disque et le temps de traitement. numérique pour cibler la bonne information. - La sécurité des types : L'instruction
if type_colonne = ...est primordiale. Si vous tentez d'utiliserGETVARCsur une colonne numérique (ou inversement), SAS générera une erreur et interrompra l'exécution. En découvrant le type en amont, notre code est immunisé contre ce problème.
Conclusion
Savoir lire une table sans en connaître la structure est une technique élégante et extrêmement puissante. En combinant la découverte des attributs (ATTRN, VARNAME, VARTYPE) avec la lecture conditionnelle (GETVARC, GETVARN), vous passez d'un code SAS figé à un code SAS dynamique capable de s'adapter à son environnement de données.
Dans le prochain volet de notre série, nous quitterons les tables SAS pour nous attaquer aux fichiers bruts externes : comment utiliser ces mêmes concepts à bas niveau pour parser et lire un fichier texte complexe que la fameuse instruction INFILE peinerait à traiter.






