In einem Makro werden mehrere Datensätze transponiert. Als Ergebnis bekomme ich:
Datensatz 1:
_NAME_
Text
Datensatz 2:
_NAME_ COL1 COL2
Text Text Text
usw...
In einem nächsten Schritt wird eine neue Variable zugewiesen und zwar automatisch für alle Datensätze. Dies soll aber nur da geschehen wo es mehr als _NAME_ gibt, also noch min COL1 existiert oder anders gesagt, wo die Anzahl der Spalten größer als 1 ist, sonst gibt es eine Fehlermeldung. Ich dachte ich pack die in ein Array und mache ne Do Schleife von 1 bis Obs aber sobald man einen Textdreher hat, funktioniert nichts mehr.
Kleines Update, dies scheint die gewünschte Anzahl zu liefern:
proc contents data=&dataliste._1 out=&dataliste._15; run;
proc sort data=&dataliste._15; by varnum; run;
data _null_;
set &dataliste._15;
call symputx("maximum",varnum);
run;
Bekomme ich mit %PUT &maximum in den Log, also dachte ich ich prüfe ob maximum größer 1 ist.
IF &maximum > 1 THEN DO;
DATA &dataliste._17;
SET &dataliste._1;
ATTRIB VARNAMEMZPALL LENGTH=$%eval(20*&obs.);
VARNAMEMZPALL = "";
RUN;
END;
Hab ich einmal mit % vorher und einmal ohne gemacht, in beiden Fällen gibt es Fehler.
Neues Update, auch so klappt es nicht:
DATA &dataliste._17;
SET &dataliste._1;
IF &maximum > 1 THEN DO;
laenge = 2345;
ATTRIB VARNAMEMZPALL LENGTH=$%eval(20*&obs.);
VARNAMEMZPALL = "";
END;
ELSE DO;
laenge = 111;
ATTRIB VARNAMEMZPALL LENGTH=$1;
VARNAMEMZPALL = "";
END;
RUN;
laenge gibt er korrekt an, mal 2345, mal 111 aber bei der Attrib Länge meckert er obwohl der Fehler nur im 111 Fall auftreten sollte und dort anfangs gar nicht dieser Code drinnen stand.
ERROR: The length of a character variable must be in the range of 1-32767.
Zuerst die Anzahl der Variablen in eine Makrovariable stellen, und dann bedingt weitermachen:
proc sql noprint;
select count(*) into :nvar from dictionary.columns
where libname = "LIBRARY" and memname = "DATASET";
quit;
%if &nvar. gt 1
%then %do;
/* bedingter Code */
%end;
Es gibt schon verschiedene Macros welche einem die Anzahl der Variablen zurückgeben.
Hier ein Beispiel: https://core.sasjs.io/mf__getattrn_8sas.html
Code Beispiel:
/*
* all macro compilieren
*/
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
data have;
length
_name_ $ 32
col1 8
;
_name_ = "sugus";
col1 = 123;
run;
%if %mf_getattrn(have,NVARS) > 1 %then %do;
proc print data=have;
run;
%end;
%else %do;
%put WARNING: nicht genug variablen;
%end;
%let dsid = %sysfunc(open(<DATASET>));
%if &dsid. > 0 %then %do;
%let varnum = %sysfunc(varnum(&dsid., <VARIABLE>));
%let dsid = %sysfunc(close(&dsid.));
%if &varnum. %then %do;
/* ... */
%end;
%end;
Leider funktioniert das nicht so. Einiges was ihr geschrieben habt ist zu kompliziert und lässt sich nicht so einfach integrieren.
Ich versuche das ganze einen Schritt vorher zu machen, vor dem transponieren. Es werden volle und leere Datensätze transponiert und dieser Fehler erscheint nur da wo ein leerer Datensatz transponiert wurde.
Heißt ich müsste abfragen ob ich einen leeren Datensatz habe oder einen mit Inhalt, beide werden transponiert aber nur da wo auch vorher Inhalt war, entstehen Spalten und dort geht es dann weiter.
Anstatt also die Spalten zu zählen, zähle ich den Inhalt des Datensatzes vor dem transponieren.
https://www.listendata.com/2017/04/number-of-observations-in-sas-data.html
Sieht dann so aus und klappt nicht:
proc sql noprint; select count(*) into :number from &dataliste.; quit; %put &number; DATA _NULL_; SET &dataliste.; CALL SYMPUTx("anzahl",number); RUN; %IF &anzahl > 0 THEN %DO; PROC TRANSPOSE DATA=&dataliste. OUT=&dataliste._1; VAR VARNAMEMZP ; RUN; DATA &dataliste._17; SET &dataliste._1; ATTRIB VARNAMEMZPALL LENGTH=$%eval(20*&obs.); VARNAMEMZPALL = ""; RUN; %ELSE %DO; PROC TRANSPOSE DATA=&dataliste. OUT=&dataliste._1; VAR VARNAMEMZP ; RUN; DATA &dataliste._17; SET &dataliste._1; ATTRIB VARNAMEMZPALL LENGTH=$1; VARNAMEMZPALL = ""; RUN; %END;
Hab das auch ohne den Call Symput Zwischenschritt probiert, also direkt mit number verglichen. number selber wird korrekt in den Log geschrieben.
Auch mal mit und ohne % davor, mit kommen Fehlermeldungen beim kompilieren, ohne kommen Fehler beim ausführen.
Vielen Dank, der Code funktioniert, komisch nur dass der andere nach dem Transpose nicht funktioniert hat.
Das Symput war dafür da um eine Variable zu generieren, geht aber auch ohne.
Neben dem fehlenden %END fehlt das % vor THEN
%IF &anzahl > 0 THEN %DO;
Wenn klar ist, dass es mindestens eine Spalte _NAME_ gibt, dann kann's auch gleich mit dem Datastep weiter gehen:
data ds1;
length _NAME_ $10;
run;
data ds2;
set ds1;
ARRAY all _ALL_;
if dim(all)=1 then put 'WARNING: Stopping operations';
else put 'NOTE: proceeding further steps';
run;
- Cheers -
First download a very generic macro %UT_VARLIST (ut_varlist.sas)
The macro is very useful for many other things!
Then in your macro, simply use the code:
%if %length(%ut_varlist(table=&transposed_table., exclude=_NAME_)) ne 0 %then %do; /* The transposed table variables other than _NAME_ */ %end;
%else %do;
%put WARNING: Table &transposed_table. created as a transpose of &input_table. has too few variables;
%end;
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!