Hallo zusammen,
ich suche eine möglichst elegante und einfache Möglichkeit bei einem SET-Statement mit mehreren Tabellen herauszufinden, ob der aktuelle Datensatz der erste Datensatz einer Tabelle ist.
Wahlweise auch gerne, ob der Satz der letzte Satz in einer Tabelle ist.
Beispiel:
data a;
input var_a;
datalines;
1
2
;
run;
data b;
input var_b;
datalines;
1
2
;
run;
data c;
set a (in = aa) end=eofa
b (in = bb);
var_c = eofa;
run;
Das end=eofa im Beispiel sollte sich idealerweise auf das Ende der Tabelle a beziehen und nicht auf das komplette Ende aller Sätze im SET-Statement anzeigen.
Hier das Ergebnis des oberen Codes (get) und was ich gerne hätte (want):
data get;
input var_a var_b var_c;
datalines;
1 . 0
2 . 0
. 1 0
. 2 1
;
run;
data want;
input var_a var_b var_c;
datalines;
1 . 0
2 . 1
. 1 0
. 2 0
;
run;
Folgender Code mit zwei SET-Statements ermöglicht mir zwar die gewünschte Verarbeitung, aber das macht aus meiner Sicht den Code sehr unübersichtlich.
data c;
set a (in = aa) end=eofa;
var_c = eofa;
output;
call missing (var_a, var_c);
if eofa then do until (eofb);
set b (in = bb) end=eofb;
output;
end;
run;
Da wären zwei Data-Steps und ein anschließendes Zusammenführen wahrscheinlich sinnvoller.
Mir geht es jedoch auch um den Lerneffekt: Kann ich das mit SAS in einem Schritt lösen?
Viele Grüße
Michael
Hallo Michael,
mit einem Retain-Statement kann man sich den Status merken und dann auswerten:
Data getwant;
retain _b 1;
set get (in=a ) want (in=b);
if b then do;
if _b then do;
_b = 0;
put "Erster Datensatz Tabelle Want " _N_=;
end;
end;
drop _b;
run;
/* EDIT */
/* oder noch besser */
Data getwant;
set get want indsname=Datei curobs=N_Dat;
if N_Dat=1 then put _N_ ": Erster Datensatz von Tabelle " Datei;
run;
Viele Grüße
Jan
Hi Jan,
super Idee, vielen Dank.
Mir kam beim zweiten Nachdenken auch noch eine Lösung (passend zu meinem Beispiel oben):
data d;
if 0 = 1 then set a nobs=nobsa;
set a b;
if _n_ = nobsa+1 then var_c = 1; else var_c = 0;
run;
Die Bedingung (erster Satz der zweiten Tabelle) ist ja erfüllt, wenn _n_ gleich Anzahl Sätze erste Tabelle plus 1 ist.
Somit ermittle ich in Zeile 1 die Anzahl Sätze der ersten Tabelle und vergleiche dann in Zeile 3.
Hier die generelle Variante:
data result;
if 0 = 1 then set have1 nobs=nobs_have1;
set have1 have2;
if _n_ = nobs_have1+1 then
start_have2 = 1;
else start_have2 = 0;
run;
Vielen Dank für die Unterstützung 🙂
Beste Grüße
Michael
Hallo Michael,
hier noch eine etwas "einfachere" Variante.
Es gibt die Möglichkeit im SET-Stement über die Option indsname= eine DataStep interne Variable mit dem Namen der jeweiligen Input-Tabelle zu erzeugen. Wenn der sich ändert, hat sich auch die Input-Tabelle geändert und das ist die Stelle, an der Du eine 1 in der boolschen Variable haben möchtest.
Im Beispiel wird in der Variable curTable gespeichert, welche Tabelle gerade dran ist, sie ist zunächst leer, über RETAIN wird der Wert über gelesene Records erhalten. Die boolsche Variable firstRecordRead wird auf 0 gesetzt. Im SET-Statement wird der Name der aktuellen Input-Tabelle in curName gespeichert. Anschließend kommt der Vergleich: Wenn curTable nicht curName entspricht (das ist bei der ersten Iteration der Fall weil curTable missing ist, dann bei jedem Wechsel der Input-Tabelle) wird firstRecordRead auf 1 gesetzt und der Name der aktuellen Input-Tabelle in curTable gespeichert.
Data c;
Length curTable $41 firstRecordRead 8;
Retain curTable;
firstRecordRead = 0;
Set a b indsname=curName;
If ( curTable Ne curName ) Then Do;
firstRecordRead = 1;
curTable = curName;
End;
*Drop curTable;
Run;
Viele Grüße,
Grischa
Vielen Dank!
Schön zu sehen, wie viele Möglichkeiten es gibt und wie ideenreich die Community ist 😉
Ich denke, die Variante mit curobs, ggf. in Kombination mit indsname sagt mir persönlich am Meisten zu.
Beste Grüße in die Runde!
Michael
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!