SAS Base  •  Module V  •  2 h
Conditions, boucles et tables multiples
M2 TIDE — Stage de programmation SAS — Enseignement 100 % distanciel
Objectifs du module
  • Écrire des traitements conditionnels avec IF/THEN/ELSE et le bloc DO/END
  • Utiliser le bloc SELECT pour différencier un traitement selon les modalités d'une variable
  • Regrouper des variables similaires dans un tableau (ARRAY) pour leur appliquer un même traitement
  • Découper une table en plusieurs sous-tables avec OUTPUT
  • Concaténer et fusionner des tables, et maîtriser les quatre types de jointures

1. La formule conditionnelle IF

Le traitement conditionnel permet de réaliser une ou plusieurs instructions selon certaines conditions.

if CONDITION then INSTRUCTION ;
else INSTRUCTION ;

La ligne ELSE n'est pas obligatoire. Si plusieurs instructions doivent être réalisées pour une même condition, il faut passer par un bloc DO ... END :

if <condition> then do ;
    <bloc d'instructions> ;
end ;
else do ;
    <bloc d'instructions> ;
end ;
data work.employes ;
    set MALIB.EMPLOYEES ;
    if COUNTRY = "USA" then TRIGRAMME = substr(DIVISION, 1, 3) ;
    else TRIGRAMME = "***" ;
    keep DIVISION TRIGRAMME COUNTRY ;
run ;
Attention à la distinction entre l'instruction IF de sélection (sans THEN, qui supprime les lignes ne vérifiant pas la condition) et l'instruction IF ... THEN de traitement conditionnel. La première ressemble à WHERE mais s'applique après la lecture, donc elle est moins performante — et elle peut porter sur des variables calculées dans l'étape DATA, ce que WHERE ne peut pas faire.

2. Le bloc SELECT

L'instruction SELECT est plus lisible qu'une série de IF lorsqu'il s'agit de différencier un traitement selon les modalités d'une même variable.

data TABLE_CREEE ;
    set TABLE_INITIALE ;
    select (VARIABLE) ;
        when (MODALITE1) instruction1 ;
        when (MODALITE2) instruction2 ;
        otherwise instruction ;
    end ;
run ;
data work.secteurs ;
    set MALIB.EMPLOYEES ;
    select (scan(DIVISION, 1, "&")) ;
        when ("INFO")  SECTEUR = "Informatique" ;
        when ("RH")    SECTEUR = "Ressources Humaines" ;
        when ("MKT")   SECTEUR = "Marketing" ;
        otherwise      SECTEUR = "Autres" ;
    end ;
run ;

3. Les boucles finies

Pour les traitements itératifs à l'intérieur d'une observation, on utilise les boucles DO.

data TABLE_CREEE ;
    set TABLE_INITIALE ;
    do i = 1 to 10 ;
        <bloc d'instructions> ;
    end ;
run ;

Nous reverrons ces structures sous leur forme macro (%DO ... %TO ... %END) au module IX, où elles servent à générer du code plutôt qu'à traiter des lignes. La différence est fondamentale et c'est l'une des confusions les plus tenaces chez les débutants en macro-langage.

4. Les tableaux (ARRAY)

Un tableau (ARRAY) regroupe plusieurs variables sous un nom commun, ce qui permet de leur appliquer le même traitement à l'intérieur d'une boucle DO, sans écrire une instruction par variable.

Contrairement à un tableau au sens R ou Python, un ARRAY SAS n'est pas un objet qui existe en dehors de l'étape DATA : c'est une facilité d'écriture, valable uniquement pendant l'exécution de l'étape DATA qui le déclare. Il doit être redéclaré dans chaque étape DATA qui l'utilise.

array NOM_TABLEAU {n} VAR1 VAR2 ... VARn ;

do i = 1 to n ;
    NOM_TABLEAU{i} = <traitement> ;
end ;

Exemple : remplacer par 0 toutes les valeurs manquantes des variables NOTE1 à NOTE5.

data work.notes ;
    set work.notes ;
    array notes{5} note1-note5 ;
    do i = 1 to 5 ;
        if notes{i} = . then notes{i} = 0 ;
    end ;
    drop i ;
run ;
La variable i créée par la boucle DO apparaît dans la table en sortie comme n'importe quelle autre variable, sauf si elle est retirée explicitement. Prenez l'habitude d'ajouter drop i ; en fin d'étape DATA quand elle ne sert qu'à parcourir le tableau.

Si les variables à regrouper partagent déjà un suffixe numérique consécutif, comme NOTE1 à NOTE5, on peut les désigner par la notation abrégée var1-varn plutôt que de toutes les nommer. C'est la même notation déjà rencontrée avec mean(of note1-note5) au module IV.

Exercice V.8 — À partir de la table WORK.NOTES (variables NOTE1 à NOTE5, valeurs manquantes possibles), utiliser un ARRAY pour remplacer toutes les valeurs manquantes d'un élève par sa moyenne calculée sur ses notes non manquantes.
Voir le corrigé
data work.notes2 ;
    set work.notes ;
    array notes{5} note1-note5 ;
    moy = mean(of note1-note5) ;
    do i = 1 to 5 ;
        if notes{i} = . then notes{i} = moy ;
    end ;
    drop i ;
run ;

La moyenne doit être calculée avant la boucle de remplacement, sinon MEAN intégrerait les zéros ou les valeurs déjà remplacées au lieu des seules notes réellement obtenues.

5. Créer plusieurs tables en une seule étape DATA

Les tables à créer doivent être déclarées au niveau de l'instruction DATA. L'instruction OUTPUT indique la table qui reçoit l'enregistrement lu.

data work.OUTPUT1 work.OUTPUT2 ;
    set work.TABLE ;
    if <CONDITION1> then output OUTPUT1 ;
    if <CONDITION2> then output OUTPUT2 ;
run ;

OUTPUT est particulièrement utile pour découper une table en plusieurs sous-tables en un seul balayage, ce qui est bien plus efficace que d'écrire autant d'étapes DATA que de sous-tables.

6. Concaténer des tables

On parle de concaténation lorsque l'on ajoute à une table les enregistrements d'une autre table : on empile des lignes. Les tables peuvent ne pas avoir le même nombre de variables.

data TABLE_SORTIE ;
    set TABLE1 TABLE2 ;
run ;

7. Fusionner des tables : MERGE et les jointures

On parle de fusion lorsque l'on ajoute à une table les variables d'une autre table : on ajoute des colonnes. Il faut alors associer correctement les observations, donc disposer d'une ou plusieurs variables identifiant les observations. C'est la clé de jointure.

data TABLE_COMMUNE ;
    merge TABLE1 TABLE2 ;
    by CLE_DE_JOINTURE ;
run ;
Les tables à fusionner doivent obligatoirement être triées sur la clé de jointure au préalable, avec la PROC SORT que nous verrons au module VI. C'est la cause d'erreur la plus fréquente sur les MERGE.

Au-delà de la clé, il faut déterminer quelles valeurs conserver en sortie. L'option IN= crée un indicateur booléen signalant si l'observation provenait de la table concernée :

data work.TABLE_COMMUNE ;
    merge work.TABLE1 (in = A)  work.TABLE2 (in = B) ;
    by CLE_DE_JOINTURE ;
    if A and not B ;
run ;

Les quatre jointures se construisent ainsi :

Jointure Condition à écrire Résultat
Jointure interne if A and B ; Uniquement les clés présentes dans les deux tables
Jointure à gauche if A ; Toutes les clés de la première table
Jointure à droite if B ; Toutes les clés de la seconde table
Jointure complète (full join) aucune condition Toutes les clés des deux tables

Un cinquième cas revient souvent en pratique : les lignes présentes dans A mais absentes de B, obtenues avec if A and not B ;. C'est la façon canonique de répondre à la question « quels clients n'ont passé aucune commande ? ».

8. Deux compléments à connaître : RETAIN, FIRST. et LAST.

L'instruction RETAIN permet de conserver la valeur d'une variable d'une itération de l'étape DATA à la suivante. C'est ce qui rend possibles les cumuls.

data destination ;
    set source ;
    retain num_obs 0 ;
    num_obs + 1 ;
run ;

SAS propose cependant une variable automatique _N_ qui désigne le nombre d'itérations réalisées de l'étape DATA en cours. Dans le cas simple d'une recopie de table, elle correspond exactement au numéro de l'observation courante :

data destination ;
    set source ;
    num_obs = _n_ ;
run ;

Lors d'une étape DATA utilisant une instruction BY, SAS crée pour chaque valeur distincte des variables d'agrégation deux variables booléennes temporaires : FIRST.variable vaut 1 si l'occurrence de la modalité est la première, LAST.variable vaut 1 si elle est la dernière.

proc sort data = SASHELP.PRDSAL3 out = work.ventes ;
    by PRODUCT ;
run ;

data work.cumul ;
    set work.ventes ;
    by PRODUCT ;
    retain ventes_cumulees 0 ;
    if first.PRODUCT then ventes_cumulees = 0 ;
    ventes_cumulees + ACTUAL ;
run ;
FIRST. et LAST. n'existent que si l'instruction BY est présente, et l'instruction BY n'est possible que si la table est triée sur la variable de groupe. Le trio SORT + BY + FIRST./LAST. est un schéma que vous réutiliserez constamment.

9. Exercices d'application

Exercice V.1 — À partir de MALIB.EMPLOYEES, tester le contenu de COUNTRY : si COUNTRY vaut USA, créer TRIGRAMME à partir des 3 premiers caractères de DIVISION, sinon inscrire « *** ». Ne conserver que DIVISION, TRIGRAMME et COUNTRY.
Voir le corrigé
data work.employes ;
    set malib.employees ;
    if country = "USA" then trigramme = substr(division,1,3) ;
    else trigramme = "***" ;
    keep division trigramme country ;
run ;
Exercice V.2 — Ajouter à l'exercice précédent une variable DIV2 contenant la seconde partie de DIVISION après le symbole &.
Voir le corrigé
data work.employes2 ;
    set malib.employees ;
    if country = "USA" then trigramme = substr(division,1,3) ;
    else trigramme = "***" ;
    div2 = scan(division, 2, "&") ;
    keep division trigramme country div2 ;
run ;
Exercice V.3 — À partir de DIVISION, créer SECTEUR avec les modalités Informatique, Ressources Humaines, Marketing ou Autres, en utilisant un bloc SELECT.
Voir le corrigé
data work.secteurs ;
    set malib.employees ;
    select (scan(division,1,"&")) ;
        when ("INFO")  secteur = "Informatique" ;
        when ("RH")    secteur = "Ressources Humaines" ;
        when ("MKT")   secteur = "Marketing" ;
        otherwise      secteur = "Autres" ;
    end ;
run ;
Exercice V.4 — À partir de SASHELP.CLASSFIT, créer en une seule étape DATA une table pour les hommes et une pour les femmes. Puis créer une table contenant les enregistrements des deux tables précédentes.
Voir le corrigé
data work.hommes work.femmes ;
    set sashelp.classfit ;
    if sex = "M" then output work.hommes ;
    else output work.femmes ;
run ;

data work.tous ;
    set work.hommes work.femmes ;
run ;
Exercice V.5 — Réaliser les quatre types de jointures entre les tables PRDSAL96 et PRDSAL97.
Voir le corrigé
proc sort data=malib.prdsale96 out=work.p96 ; by product ; run ;
proc sort data=malib.prdsale97 out=work.p97 ; by product ; run ;

data work.interne ;
    merge work.p96 (in=a)  work.p97 (in=b) ;
    by product ;
    if a and b ;
run ;

data work.gauche ;
    merge work.p96 (in=a)  work.p97 (in=b) ;
    by product ;
    if a ;
run ;

data work.droite ;
    merge work.p96 (in=a)  work.p97 (in=b) ;
    by product ;
    if b ;
run ;

data work.complete ;
    merge work.p96 (in=a)  work.p97 (in=b) ;
    by product ;
run ;
Exercice V.6 — À partir de SASHELP.PRDSAL3, ne conserver que les états du Texas, en date du 1er janvier 1997, pour le produit BED, avec les variables STATE PRODUCT DATE ACTUAL. Dans la même étape DATA, créer un compteur et une variable de ventes cumulées à l'aide de RETAIN.
Voir le corrigé
data work.texas ;
    set sashelp.prdsal3 ;
    where state = "TX" and date = "01JAN1997"d and product = "BED" ;
    keep state product date actual ;
    retain compt 0  ventes_cumulees 0 ;
    compt + 1 ;
    ventes_cumulees + actual ;
run ;
Exercice V.7 — Reprendre l'exercice précédent pour obtenir un cumul de ventes redémarrant à chaque changement de produit, à l'aide de FIRST.
Voir le corrigé
proc sort data=sashelp.prdsal3 out=work.tri ;
    by product ;
    where state = "TX" and date = "01JAN1997"d ;
run ;

data work.cumul_produit ;
    set work.tri ;
    by product ;
    retain ventes_cumulees ;
    if first.product then ventes_cumulees = 0 ;
    ventes_cumulees + actual ;
run ;

Le retour à zéro à chaque first.product est ce qui distingue ce cumul à remise à zéro d'un cumul global comme celui de l'exercice V.6.
Point de contrôle — à faire avant de continuer
Sur l'exercice V.5, comptez le nombre de lignes obtenu pour chacune des quatre jointures. Si les quatre nombres sont identiques, quelque chose ne va pas : vérifiez que vos tables sont bien triées et que la clé de jointure a le même type dans les deux tables.
Pour valider ce module
  • QCM — QCM Module V — 5 questions, auto-évaluation
Modifié le: jeudi 10 septembre 2026, 14:24
Accessibilité

Couleur de fond Couleur de fond

Police Police

Crénage de la police Crénage de la police

Visibilité de l’image Visibilité de l’image

Hauteur de ligne Hauteur de ligne

1.2

Surbrillance de lien Surbrillance de lien

Alignement du texte Alignement du texte

Taille de police Taille de police

1

Espacement des lettres Espacement des lettres

0

Couleur de texte Couleur de texte

Largeur de paragraphe Largeur de paragraphe

0