SAS9

Das IF vs WHERE Duell und die Falle der SUBSTR Funktion

Simon 6 vues

Manchmal stürzt ein SAS©-Programm mit einer IF-Anweisung ab, funktioniert aber einwandfrei, wenn man dieses IF durch ein WHERE ersetzt. Ist das Magie? Nein, es ist ein architektonischer Unterschied.

Ein Forum-Nutzer stieß auf einen kryptischen Fehler: "INVALID THIRD ARGUMENT TO FUNCTION SUBSTR". Analysieren wir diesen Musterfall, um die interne Funktionsweise von SAS© zu verstehen.

1. Der fehlerhafte Code

Der Benutzer möchte seine Daten je nach Provinz in zwei Tabellen aufteilen. Er verwendet eine komplexe Logik, die SUBSTR, TRIM und LEFT beinhaltet.

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;

Der Fehler:

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

Warum beschwert sich SAS© über das 3. Argument von SUBSTR (die angeforderte Länge), obwohl die Variable BRPROV 18 Zeichen lang ist?

2. Die Diagnose: Die TRIM-Falle

Der Fehler liegt nicht an der ursprünglichen Variable, sondern daran, was der Code bevor er SUBSTR aufruft, damit macht.

Betrachten wir die Abfolge der Funktionen für den Wert "ALBERTA":

  1. LEFT(BRPROV): Richtet den Text linksbündig aus.

  2. TRIM(...): Entfernt nachgestellte Leerzeichen.

    • Temporäres Ergebnis: Die Zeichenkette wird zu "ALBERTA" (Länge = 7).

  3. SUBSTR(..., 1, 12): Der Code versucht dann, 12 Zeichen zu extrahieren, um zu prüfen, ob es sich um "SASKATCHEWAN" handelt.

Der Absturz: Sie fordern SAS© auf, 12 Zeichen aus einer Zeichenkette zu extrahieren, die nur noch 7 Zeichen lang ist (wegen TRIM). Das ist mathematisch unmöglich, daher bricht der Data Step ab.

3. Die Schlüsselfrage: Warum funktioniert WHERE?

Der Benutzer bemerkt: "Wenn ich WHERE anstelle von IF verwende, erhalte ich keine Fehlermeldung."

Hier liegt der grundlegende Unterschied:

IF (Data Step)

  • Zeitpunkt: Wird während der Verarbeitung jeder Zeile im PDV (Program Data Vector) ausgeführt.

  • Verhalten: Manipuliert die Daten nach der Transformation. Hier sieht es das Ergebnis von TRIM (die gekürzte Zeichenkette) und schlägt fehl. Außerdem kann SAS© gemäß den Regeln der logischen Auswertung versuchen, den zweiten Teil des OR auszuwerten, auch wenn der erste ausreichend erscheint, oder einfach bei der Kompilierung der Argumente fehlschlagen.

WHERE (Pre-Filter)

  • Zeitpunkt: Wird bevor die Daten in den Data Step gelangen, ausgeführt.

  • Verhalten: Wirkt wie ein SQL-Filter auf die Datenquelle.

  • Warum funktioniert es? Die WHERE-Anweisung ist oft "intelligenter" oder "restriktiver" bei den Funktionen, die sie zulässt. Oft ignoriert sie kosmetische Funktionen wie TRIM und basiert auf den Metadaten der Quellspalte (die tatsächlich 18 Zeichen lang ist), oder optimiert die Abfrage anders.

4. Die Lösungen (Best Practices)

Anstatt sich auf die Toleranz von WHERE zu verlassen, muss die Logik des Codes korrigiert werden.

Lösung A: TRIM entfernen (Der einfache Ansatz)

Wie ein Benutzer vorschlägt, ist TRIM hier unnötig. SUBSTR funktioniert sehr gut mit einer Zeichenkette mit Leerzeichen, solange die ursprüngliche Variable lang genug ist.

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

Lösung B: Der "Starts With" Operator =: (Der Profi-Ansatz)

SAS© besitzt einen spezifischen Operator, um "beginnt mit" auszudrücken, was das Zählen von Zeichen und die Verwendung von SUBSTR vermeidet.

Dies ist der Operator =: (gleich gefolgt von zwei Punkten).

Optimierter Code:

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;
AnweisungRolleFehlerbehandlung
IFProgrammierlogik. Zeile für Zeile auf die Werte im Speicher angewendet.Streng. Wenn Sie eine kurze Zeichenkette erstellen (TRIM) und eine lange Lesung anfordern (SUBSTR), stürzt es ab.
WHEREEingangsfilter (E/A). Wird auf die Quelldatei angewendet.Robuster, da oft mit Rohmetadaten oder über die SQL-Engine gearbeitet wird.

Experten-Tipp: Wenn Sie den Anfang einer Zeichenkette überprüfen müssen, vergessen Sie SUBSTR. Verwenden Sie immer den Operator =:. Das ist lesbarer, schneller und weniger fehleranfällig hinsichtlich der Länge.