SAS est un logiciel merveilleux, mais tous n’y ont pas accès. Pour contenter la soif de données de vos collègues qui n’auraient pas d’autre outil à disposition, vous envisagez d’envoyer vos données SAS dans une feuille Excel. Et là, le drame se noue : comment vous y prendre ? Nous passons en revue 6 méthodes qui nécessitent des installations, des manipulations et des licences différentes : il y en aura forcément une qui vous conviendra.
L’export en fichier plat
La procédure Export permet de créer des fichiers texte (ou fichiers plats) à partir d’une table SAS. Différents formats sont possibles, dont CSV ; il faut se méfier de celui-ci, puisqu’il correspond aux spécifications américaines du format CSV (séparateur virgule entre les données et point comme séparateur décimal). Il est préférable de se tourner vers le format « Delimiter » et de proposer la tabulation comme séparateur de données.
Avantage non négligeable : ce programme fonctionne aussi bien sur un serveur que sur SAS PC, avec une simple licence SAS Base.
PROC EXPORT DATA = tableSAS OUTFILE = "chemin et nom du fichier créé" DBMS = DLM REPLACE ; DELIMITER = "09"x ; /* séparateur tabulation */ RUN ;
L’inconvénient majeur de cet export est l’abandon des labels des variables. Les valeurs sont en revanche exportées : les valeurs contenues dans le fichier plat sont celles qui s’affichent à l’ouverture de la table dans SAS.
Il est conseillé d’avoir, dans une étape préalable, modifié les formats des variables ayant des décimales pour NUMX. et les formats des dates pour DDMMYY10. (Ici, la table VENTES est un clone de la table SASHELP.PRDSALE qui sera utilisée dans tous les exemples.)
PROC DATASETS LIB = work NOLIST ; MODIFY ventes ; FORMAT actual predict NUMX12.2 month DDMMYY10. ; RUN ; QUIT ; PROC EXPORT DATA = work.ventes OUTFILE = "c:\temp\dlm.txt" DBMS = DLM REPLACE ; DELIMITER = "09"x ; RUN ;
L’export en classeur Excel
Une variante de la méthode précédente consiste à reprendre la proc Export mais en précisant comme format du fichier créé un classeur Excel. Cependant, il faut pour cela posséder une licence pour le module SAS Access to PC Files et exécuter le programme sur SAS PC.
PROC EXPORT DATA = tableSAS OUTFILE = "chemin et nom du fichier créé" DBMS = EXCEL REPLACE ; SHEET = "nomFeuille" ; /* nom de la feuille Excel créée */ RUN ;
Avec SAS 9 il est possible d’indiquer le nom de la feuille Excel qu’on alimente avec les données et ainsi d’aller insérer une nouvelle feuille dans un classeur existant. Attention, le nom de la feuille ne doit pas se terminer par un $ ni compter plus de 32 caractères.
Par rapport à l’export en fichier plat, il n’est pas nécessaire de modifier les formats au préalable. En revanche, les labels ne sont toujours transmis par cette méthode.
PROC EXPORT DATA = work.ventes OUTFILE = "c:\temp\excel.xls" DBMS = EXCEL REPLACE ; SHEET = "ventes" ; RUN ;
La pseudo-bibliothèque
La version 9 de SAS propose, sur PC et avec la licence SAS/ACCESS TO PC FILES (donc à configuration identique que pour la proc Export DBMS=EXCEL), il est possible de déclarer une bibliothèque SAS vers un classeur Excel.
LIBNAME nomBib EXCEL "chemin et nom du classeur.xls" ;
On écrit ensuite dans cette bibliothèque comme dans n’importe quelle autre, créant ainsi des onglets différents en fonction des noms donnés aux différentes « tables » qui y sont écrites.
LIBNAME test EXCEL "c:\temp\test.xls" ; DATA test.ventes ; SET sashelp.prdsale ; FORMAT actual predict NLNUM12.2 ; RUN ; PROC CONTENTS DATA = sashelp.prdsale ; ODS OUTPUT variables = test.dictionnaire ; RUN ; LIBNAME test CLEAR ;
Attention, il n’est pas possible de remplacer un onglet déjà existant. On ne peut donc écrire qu’en utilisant des noms de « tables » encore absents du classeur cible.
L’export via ODS : au format HTML
La solution de l’ODS est plus souple : au lieu d’exporter des données, on envoie vers Excel le résultat d’une procédure. Cela donne une énorme souplesse sur les labels, les formats, et la mise en forme (tableau, liste) des résultats.
Le moyen le plus ancien pour envoyer des résultats lisibles par Excel via l’ODS est de créer un document HTML auquel on donnera une extension .XLS ; ce fichier sera spontanément ouvert par Excel et converti. La manœuvre fonctionne avec toutes les versions d’Excel supérieures à Excel 95. On peut donc considérer qu’elle fonctionnera quelle que soit la version utilisée par le destinataire du fichier.
L’inconvénient principal est qu’on ne produit pas du « vrai Excel » ; et donc on ne peut pas écrire dans plusieurs feuilles à l’intérieur d’un même classeur. On ne peut pas non plus intégrer de vrais en-têtes et pieds de pages qui ne seraient visibles qu’à l’impression, ni figer des colonnes, ni proposer des filtres automatiques d’emblée. Ce sera une feuille de données inerte qui sera transmise par SAS à Excel.
ODS HTML FILE = "chemin et nom du fichier créé" <options>; PROC xxx … ; … RUN ; ODS HTML CLOSE ;
Ce mode de fonctionnement est accepté par toutes les versions de SAS à partir de la 8.0 et sur toutes les plate-formes, avec comme seul module requis SAS/Base – et bien sûr le module rattaché à la procédure utilisée au milieu du « sandwich » ODS.
On peut également envoyer par ce biais le contenu de plusieurs tables dans une seule feuille Excel : il suffit d’enchaîner les procédures avant l’instruction ODS HTML CLOSE. Les sorties des procédures seront incluses les unes à la suite des autres dans le résultat.
TITLE ; ODS HTML FILE = "c:\temp\ods html.xls" ; PROC PRINT DATA = work.ventes ; VAR country product actual predict ; RUN ; ODS HTML CLOSE ;
On peut également profiter du format HTML pour ajouter des options de mise en forme à travers les procédures Print, Tabulate et Report. On peut ainsi, à travers les options STYLE, indiquer des couleurs (de police et de fond de cellule), des polices en gras, en italique, des tailles de caractères, etc. Ces mises en forme peuvent être fixes ou conditionnelles à la valeur de la cellule (voire de la ligne ou de la colonne entière avec la proc Report), à travers des formats (et des blocs COMPUTE dans Report).
On peut même utiliser (avec prudence car ces attributs en sont pas pris en compte dans SAS et sont donc dépendants de la pérennité de leur interprétation dans Excel) des instructions de mise en forme spécifiques à Microsoft Office dans la propriété HTMLSTYLE. L’exemple ci-dessous indique comment afficher les éléments d’un tableau avec un angle de 45° par rapport à l’horizontale.
ODS HTML FILE = "c:\temp\rotation.xls" ; PROC TABULATE DATA = work.ventes ; CLASS product country ; CLASSLEV product / STYLE = [HTMLSTYLE="mso-rotate:45" CELLHEIGHT=70px] ; VAR actual predict ; TABLE country="" * (actual predict) * F = 7., product="" * MEAN = "" ; RUN ; ODS HTML CLOSE ;
On peut profiter des options de l’ODS pour générer automatiquement plusieurs classeurs Excel séparés. On utilisera à cet effet l’option NEWFILE dans l’instruction ODS : on peut alors changer de classeur Excel à chaque nouvelle procédure (NEWFILE=PROC), à chaque nouveau tableau (NEWFILE=TABLE) ou à chaque valeur d’une variable BY (NEWFILE=BYGROUP). Les noms des classeurs générés sont dérivés automatiquement du nom fourni dans l’option FILE par une numérotation automatique.
ODS HTML FILE = "c:\temp\par pays1.xls" NEWFILE = TABLE ; PROC TABULATE DATA = work.ventes ; CLASS product country ; CLASSLEV product / STYLE = [HTMLSTYLE="mso-rotate:45" CELLHEIGHT=70px] ; VAR actual predict ; TABLE country = "", /* un tableau par pays */ (actual predict) * F = 7., product="" * MEAN = "" / BOX = _PAGE_ ; RUN ; ODS HTML CLOSE ;
L’export via ODS : au format XML
Les versions les plus récentes d’Excel (2002 et supérieures) savent lire, en plus des formats XLS, HTML et texte déjà évoqués, un type spécifique de fichiers XML. SAS peut, depuis la version 9, de manière expérimentale, produire ce genre de fichiers. On utilise pour cela encore l’ODS mais avec une destination appelée TAGSETS.EXCELXP.
ODS TAGSETS.EXCELXP FILE = "chemin et nom du fichier créé" < options communes ODS > < OPTIONS (nomOption="valeur") > ; PROC xxx … ; … RUN ; ODS HTML CLOSE ;
On retrouve dans cette syntaxe quelque peu atypique deux niveaux d’options. Certaines sont communes à tous les types de XML produits par l’ODS : NEWFILE, STYLE par exemple. D’autres sont à spécifier derrière le mot-clé OPTIONS et sont spécifiques au format « XML vers Excel ».
ODS TAGSETS.EXCELXP FILE = "c:\temp\xml.xls" ; PROC TABULATE DATA = work.ventes ; CLASS product country ; VAR actual predict ; TABLE country = "", (actual predict) * F = 7., product="" * MEAN = "" / BOX = _PAGE_ ; RUN ; ODS TAGSETS.EXCELXP CLOSE ;
Par défaut, chaque tableau généré va dans une feuille différente du même classeur. L’option NEWFILE, identique à ODS HTML, permet de générer plusieurs classeurs. L’option SHEET_INTERVAL permet de paramétrer le moment auquel on passe, dans un même classeur, à un onglet différent.
PROC SORT DATA = work.ventes ; BY product ; RUN ; ODS TAGSETS.EXCELXP FILE = "c:\temp\série xml 1.xls" NEWFILE = PROC OPTIONS (SHEET_INTERVAL="BYGROUP") ; PROC TABULATE DATA = work.ventes FORMAT = 7. ; BY product ; CLASS country ; VAR actual predict ; TABLE country="", (actual predict)* MEAN="" ; RUN ; PROC TABULATE DATA = work.ventes FORMAT = 7. ; BY product ; CLASS year quarter ; VAR actual predict ; TABLE year=""* quarter="", (actual predict)* MEAN="" ; RUN ; ODS TAGSETS.EXCELXP CLOSE ;
Voici une liste des principales options spécifiques à ce format XML pour Excel.
Option | Valeurs possibles
(par défaut) |
Usage | |
Contenu feuille | FROZEN_HEADERS | NO, YES | Fige la ligne d’en-tête des colonnes (cf. fractionnement) |
AUTOFILTER | NONE, ALL, un intervalle (3-5 par exemple) | Crée des filtres automatiques sur toutes les colonnes ou sur certaines (intervalle avec les n° de colonnes en partant de A) | |
FORMULAS | YES, NO | Accepte les formules dans les valeurs proposées depuis SAS pour les cellules Excel | |
CONVERT_PERCENTAGES | YES, NO | Yes : les pourcentages (au format PERCENT dans SAS) sont convertis en pourcentages Excel | |
MISSING_ALIGN | R, L, C | Justification des valeurs manquantes | |
Feuilles | SHEET_INTERVAL | TABLE, PAGE, BYGROUP, PROC, NONE | Spécifie quand on change de feuille dans le classeur (à chaque tableau, saut de page, groupe BY, procédure, jamais) |
SHEET_NAME | NONE, texte | Nom de base des feuilles (agrémenté d’un compteur automatique) | |
SHEET_LABEL | NONE, texte | Permet de remplacer la fin du nom automatique de la feuille
les noms automatiques sont : « Proc nbDeProcs – label » ; « Page nbDePages – label » ; « Table nbDeFeuilles – label » ; « By nbDeFeuillesParBy – label » |
|
CONTENTS | NO, YES | Crée une feuille contenant une table des matières des autres feuilles | |
INDEX | NO, YES | Crée une feuille contenant un index des autres feuilles | |
Impression | ORIENTATION | PORTRAIT, LANDSCAPE | Orientation à l’impression |
ZOOM | 100, un nombre | Valeur du zoom d’affichage | |
SCALE | 100, un nombre | Valeur du zoom d’impression | |
BLACKANDWHITE | NO, YES | Imprime en noir et blanc | |
DRAFTQUALITY | NO, YES | Imprime en qualité brouillon | |
GRIDLINES | NO, YES | Affiche le quadrillage automatique à l’impression | |
FITTOPAGE | NO, YES | Ajuste le zoom d’impression pour faire tenir la feuille dans une page | |
EMBEDDED_TITLES | NO, YES | YES : les Footnotes SAS sont considérés comme pieds de page Excel et pas affichés directement dans la feuille de calcul
On peut insérer des éléments spéciaux dans les Footnotes tels que : %NRSTR(&p) le n° de page ; %NRSTR(&t) le nombre total de pages ; %NRSTR(&h) l’heure de création du document ; %NRSTR(&j) le jour de création du document ; %NRSTR(&a) le nom de l’onglet courant ; %NSTR(&n) le nom du classeur Excel ; %NRSTR(&z) le répertoire de stockage du classeur. Attention ces codes ne sont pas interprétés à l’identique par toutes les versions d’Excel !!! |
|
SUPPRESS_BYLINES | NO, YES | YES : les lignes de séparation de blocs BY n’apparaissent pas dans la feuille. Ne pas utiliser l’option NOBYLINE de SAS car conflit avec cette destination de l’ODS. | |
DOC | HELP, QUICK | Niveau de documentation affichée dans la Log à l’exécution de l’instruction ODS |
ODS TAGSETS.EXCELXP FILE = "c:\temp\liste.xls" OPTIONS(AUTOFILTER="ALL") ; PROC PRINT DATA = sashelp.prdsale NOOBS LABEL ; FORMAT actual predict 12.2 ; RUN ; ODS TAGSETS.EXCELXP CLOSE ;
Mises en garde
- Les variables numériques ne doivent pas avoir de formats affichant une virgule comme séparateur décimal sinon Excel les reçoit comme variable texte.
- Les nombres à afficher avec des zéros liminaires sont à spécifier avec une option de style dans la procédure d’affichage (Print, Tabulate ou Report) appelée TAGATTR (exemple ci-dessous).
ODS TAGSETS.EXCELXP FILE = "c:\temp\liste naf.xls" OPTIONS(AUTOFILTER="ALL") ; PROC PRINT DATA = work.naf NOOBS LABEL ; VAR code / STYLE(DATA)=[TAGATTR="format:00"] ; VAR libelle ; RUN ; ODS TAGSETS.EXCELXP CLOSE ;
L’export direct de données via un lien DDE
La dernière possibilité consiste à écrire directement dans Excel depuis SAS. On utilise pour cela un lien DDE, tuyauterie Windows permettant à deux applications de s’échanger des informations. Pour cela, il faut qu’Excel soit ouvert. Il faut également avoir SAS (client lourd) installé sur le PC (il ne suffit pas d’avoir SAS Enterprise Guide par exemple).
Le dialogue se fait en 2 temps.
- On déclare l’existence d’un lien DDE entre SAS et Excel dans SAS, au moyen d’un Filename particulier ; ce lien pointe vers une plage de cellules dans une feuille donnée du classeur Excel ouvert.
- On écrit des données dans ce lien comme dans un fichier plat à séparateur tabulation.
On peut également envoyer à Excel des instructions pour qu’il accomplisse automatiquement un certain nombre de tâches (ouvrir un classeur existant, sauvegarder, trier, etc.) à l’aide d’un autre lien DDE, pointant non pas vers des cellules mais vers l’application Excel. On envoie alors des commandes écrites en langage macro Excel 4 (mais pas en Visual Basic). On trouvera l’aide et l’index complet de ces commandes dans le package « macrofun.exe » disponible sur le site de Microsoft (rechercher simplement le nom de ce fichier sur Google pour avoir la page de téléchargement).
L’avantage majeur de cette méthode est de ne nécessiter aucun autre module que SAS Base pour fonctionner. En revanche, elle n’est pas utilisable pour qui n’a pas SAS installé sur son poste.
L’ouverture automatique d’Excel peut se réaliser depuis SAS, au moyen d’une commande système (SYSTASK COMMAND ou X). Il faut ensuite laisser à Excel le temps de s’ouvrir (avec une commande de mise en sommeil de SAS, SLEEP) avant de continuer le programme et d’envoyer des données.
SYSTASK COMMAND "Start Excel" ; DATA _NULL_ ; CALL SLEEP(10,1) ; /* on attend 10 secondes */ RUN ;
On définit alors le lien DDE : vers le logiciel Excel, le chemin est « Excel|system » ; vers le classeur ouvert, c’est
« Excel|nomDeLaFeuille!L1èreLigneC1èreColonne:LdernièreLigneCdernièreColonne »
FILENAME xlAppli DDE "Excel|system" ; FILENAME xlData DDE "Excel|Feuil1!L1C1:L19C5" NOTAB ;
Dans le 2e filename ci-dessus, on pointe vers une plage de cellules qui va de (ligne 1, colonne 1) à (ligne 19, colonne 5). L’option NOTAB permet de sécuriser le passage d’une cellule à sa voisine, uniquement par l’écriture d’une tabulation (par défaut, c’est l’espace qui fait changer de cellule, d’où des décalages avec certaines zones de texte contenant des caractères blancs).
DATA _NULL_ ; FILE xlData ; SET sashelp.class ; PUT name "09"x age "09"x sex "09"x weight NUMX12.2 "09"x height NUMX12.2 ; RUN ;
Pour les données dates et nombres, il convient de leur appliquer un format qu’Excel soit capable de comprendre : DDMMYY, MMYYS pour les dates et NUMX pour les nombres. Pour obtenir des zéros en tête d’une valeur, il faut d’abord écrire la valeur avec le lien vers les cellules, puis dicter une mise en forme avec le lien vers l’application Excel.
On peut exporter l’intégralité d’une table vers Excel par le biais du macro-programme suivant.
%MACRO sas2excel (tableSAS, classeurExcel, onglet=Feuil1) ; FILENAME cible "&classeurExcel" ; SYSTASK COMMAND "Start Excel" ; DATA _NULL_ ; CALL SLEEP(10,1) ; RUN ; FILENAME xlAppli DDE "Excel|system" ; %IF %SYSFUNC(FEXIST(cible))=1 %THEN %DO ; DATA _NULL_ ; FILE xlAppli ; PUT "[OPEN(""&classeurExcel"")]" ; RUN ; %END ; DATA _NULL_ ; FILE xlData ; RUN ; %IF &syserr >= 4 %THEN %DO ; /* la feuille demandée n'existe pas */ %ABORT ; %END ; PROC CONTENTS DATA = &tableSAS OUT = work.dictionnaire NOPRINT ; RUN ; PROC SQL NOPRINT ; SELECT COMPBL(name!! CASE WHEN (type=1 AND format IS MISSING) THEN " NUMX15.2 " WHEN (type=1) THEN " "!! COMPRESS(format!! formatL!!"."!! formatD)!!" " ELSE "" END), QUOTE(LEFT(TRIM(COALESCE(label,name)))), COUNT(*), MAX(nobs)+1 INTO : variables SEPARATED BY " '09'x ", : en_tete SEPARATED BY " '09'x ", : nbVar , : nbObs FROM work.dictionnaire ORDER BY varnum ; DROP TABLE work.dictionnaire ; QUIT ; FILENAME xlData DDE "Excel|&onglet!L1C1:%SYSFUNC(COMPRESS(L&nbObs.C&nbVar))" NOTAB ; DATA _NULL_ ; FILE xlData LRECL = 5000 ; SET &tableSAS ; IF _N_ = 1 THEN PUT &en_tete ; PUT &variables ; RUN ; DATA _NULL_ ; FILE xlAppli ; PUT %IF %SYSFUNC(FEXIST(cible))=1 %THEN %DO ; "[SAVE()]" %END ; %ELSE %DO ; "[SAVE.AS(""&classeurExcel"")]" %END ; ; PUT "[QUIT()]" ; RUN ; %MEND sas2excel ;
Ce programme récupère automatique les noms des variables, leurs labels, la présence d’éventuels formats, et génère l’étape Data d’export. Il ouvre également Excel, vérifie l’existence du classeur pour l’ouvrir ou en ouvre un vierge, vérifie l’existence de l’onglet dans lequel il doit écrire (mais ne sait malheureusement pas créer un onglet portant un nom prédéterminé).
Pour l’application d’un format, il faut d’abord écrire les données, puis revenir sélectionner les cellules (fonction SELECT) et enfin modifier leur format. L’exemple suivant affiche des numéros de départements avec un zéro liminaire sur 2 chiffres.
FILENAME xlData DDE "Excel|Feuil1!L2C1:L97C2" NOTAB ; DATA _NULL_ ; FILE xlData ; SET maps.france2 ; PUT id "09"x idname ; RUN ; FILENAME xlAppli DDE "Excel|System" ; DATA _NULL_ ; FILE xlAppli ; PUT "[SELECT(""L2C1:L97C1"")]" ; PUT "[FORMAT.NUMBER(""0#"")]" ; RUN ;
Une utilisation possible du lien DDE est de créer une destination ODS à même d’écrire dans le tuyau DDE en envoyant les sorties d’une procédure séparées par des tabulations et des retours à la ligne. Il s’agit d’un jeu de balises à définir (un markup) qui sera stocké dans la bibliothèque SASUSER de l’utilisateur.
Voici le code de ce markup.
PROC TEMPLATE; DEFINE TAGSET Tagsets.xlDDE; DEFINE EVENT header; START: TRIGGER data; FINISH: TRIGGER data; END; DEFINE EVENT row ; FINISH: PUT NL ; END ; DEFINE EVENT data; START: PUT value "09"x ; END; END; RUN;
On l’utilise ensuite dans une instruction ODS MARKUP qui pointe vers une plage de cellules préalablement définie par un FILENAME DDE. On peut prévoir cette plage assez grande pour ne pas se soucier de calculer sa taille exacte. On a alors un bon moyen d’envoyer les sorties d’une procédure dans un classeur Excel existant, exactement dans une plage de cellules prévue d’avance (en termes de mise en forme par exemple).
FILENAME excel DDE "Excel|Feuil1!L1C1:L200C6" NOTAB ; ODS MARKUP TYPE=xlDDE FILE = excel ; PROC MEANS DATA = sashelp.prdsale MAXDEC = 0 NONOBS SUM MEAN MEDIAN STD ; VAR actual ; CLASS product country ; RUN ; ODS MARKUP CLOSE ;