SAS9

Le duel IF vs WHERE et le piège de la fonction SUBSTR

Simon 7 vistas

Il arrive parfois qu'un programme SAS© plante avec une instruction IF, mais fonctionne parfaitement si l'on remplace ce IF par un WHERE. Est-ce de la magie ? Non, c'est une différence d'architecture.

Un utilisateur du forum s'est heurté à une erreur cryptique : "INVALID THIRD ARGUMENT TO FUNCTION SUBSTR". Analysons ce cas d'école pour comprendre la mécanique interne de SAS©.

1. Le Code Coupable

L'utilisateur souhaite diviser ses données en deux tables selon la province. Il utilise une logique complexe impliquant SUBSTR, TRIM et LEFT.

1DATA bundrpt regulert;
2 SET combine;
3 /* La condition qui plante */
4 IF (substr(trim(left(brprov)),1,7) = 'ALBERTA') OR
5 (substr(trim(left(brprov)),1,12) = 'SASKATCHEWAN' and put(cidkey,sask.) = 'Y')
6 THEN OUTPUT bundrpt;
7 ELSE OUTPUT regulert;
8RUN;

L'erreur :

NOTE: INVALID THIRD ARGUMENT TO FUNCTION SUBSTR AT LINE 302 BRPROV=ALBERTA

Pourquoi SAS© se plaint-il du 3ème argument de SUBSTR (la longueur demandée) alors que la variable BRPROV fait 18 caractères de long ?

2. Le Diagnostic : Le piège du TRIM

L'erreur ne vient pas de la variable d'origine, mais de ce que le code en fait avant d'appeler SUBSTR.

Regardons l'enchaînement des fonctions pour la valeur "ALBERTA" :

  1. LEFT(BRPROV) : Aligne le texte à gauche.

  2. TRIM(...) : Supprime les espaces à droite.

    • Résultat temporaire : La chaîne devient "ALBERTA" (longueur = 7).

  3. SUBSTR(..., 1, 12) : Le code tente ensuite d'extraire 12 caractères pour vérifier si c'est "SASKATCHEWAN".

Le Crash : Vous demandez à SAS© d'extraire 12 caractères d'une chaîne qui n'en fait plus que 7 (à cause du TRIM). C'est mathématiquement impossible, donc le Data Step s'arrête.

3. La Question Clé : Pourquoi WHERE fonctionne ?

L'utilisateur note : "Si je mets WHERE à la place de IF, je n'ai pas de message d'erreur."

C'est là que réside la différence fondamentale :

IF (Data Step)

  • Moment : S'exécute pendant le traitement de chaque ligne, dans le PDV (Program Data Vector).

  • Comportement : Il manipule les données après transformation. Ici, il voit le résultat du TRIM (la chaîne raccourcie) et échoue. De plus, selon les règles d'évaluation logique, SAS© peut tenter d'évaluer la deuxième partie du OR même si la première semble suffire, ou échouer simplement lors de la compilation des arguments.

WHERE (Pre-Filter)

  • Moment : S'exécute avant que les données n'entrent dans le Data Step.

  • Comportement : Il agit comme un filtre SQL sur la source de données.

  • Pourquoi ça passe ? L'instruction WHERE est souvent plus "intelligente" ou plus "restrictive" sur les fonctions qu'elle autorise. Souvent, elle ignorera les fonctions cosmétiques comme TRIM pour se baser sur la métadonnée de la colonne source (qui fait bien 18 caractères), ou optimisera la requête différemment.

4. Les Solutions (Best Practices)

Plutôt que de compter sur la tolérance du WHERE, il faut corriger la logique du code.

Solution A : Supprimer le TRIM (L'approche simple)

Comme le suggère un utilisateur, le TRIM est inutile ici. SUBSTR fonctionne très bien sur une chaîne avec des espaces, tant que la variable d'origine est assez longue.

1/* Pas de TRIM, donc on travaille sur les 18 caractères d'origine */
2IF substr(brprov, 1, 7) = 'ALBERTA' ...

Solution B : L'opérateur "Starts With" =: (L'approche Pro)

SAS© possède un opérateur spécifique pour dire "Commence par", ce qui évite d'avoir à compter les caractères et d'utiliser SUBSTR.

C'est l'opérateur =: (égal suivi de deux points).

Code optimisé :

1DATA bundrpt regulert;
2 SET combine;
3 /* Plus de SUBSTR, plus de TRIM, plus d'erreurs de longueur ! */
4 IF brprov =: 'ALBERTA' OR
5 (brprov =: 'SASKATCHEWAN' and put(cidkey,sask.) = 'Y')
6 THEN OUTPUT bundrpt;
7 ELSE OUTPUT regulert;
8RUN;
InstructionRôleGestion des erreurs
IFLogique de programmation. S'exécute ligne à ligne sur les valeurs en mémoire.Strict. Si vous créez une chaîne courte (TRIM) et demandez une lecture longue (SUBSTR), ça plante.
WHEREFiltre d'entrée (I/O). S'exécute sur le fichier source.Plus robuste car travaille souvent sur les métadonnées brutes ou via le moteur SQL.

Le conseil de l'expert : Si vous devez vérifier le début d'une chaîne de caractères, oubliez SUBSTR. Utilisez toujours l'opérateur =:. C'est plus lisible, plus rapide, et moins sujet aux erreurs de longueur.