LesezeichenAbonnierenRSS-Feed abonnieren
Dvdscot
Obsidian | Level 7

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.

 

13 ANTWORTEN 13
Dvdscot
Obsidian | Level 7

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.

Dvdscot
Obsidian | Level 7

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.

Kurt_Bremser
Super User

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;
BrunoMueller
SAS Super FREQ

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;
jh_ti_bw
Obsidian | Level 7
%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;
    
Dvdscot
Obsidian | Level 7

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.

Dvdscot
Obsidian | Level 7

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.

basefan
Obsidian | Level 7
Hallo,
vor der Zeile
%else %do;
fehlt eine Zeile mit
%END;

Der proc sql mit select into :number hat aber nichts mit dem folgenden data _null_ step zu tun? Oder doch? Wenn ja, dann ist die Frage, was mit dem data _null_ step beabsichtigt ist.

Viele Grüße
Hans
Dvdscot
Obsidian | Level 7

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.

BrunoMueller
SAS Super FREQ

Neben dem fehlenden %END fehlt das % vor THEN

%IF &anzahl > 0 THEN %DO;
basefan
Obsidian | Level 7
Hallo,
"geht aber auch ohne" kann eigentlich nicht sein. Denn nach dem Data Step mit dem call symput wird die Macro-Variable abgefragt, die mit dem call symput erzeugt wird. Also kann es nicht ohne gehen.
Wahrscheinlich existierte die Macro-Variable von vorigen Tests in der gleichen Session.

Viele Grüße
Hans
Oligolas
Barite | Level 11

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 -

DavePrinsloo
Pyrite | Level 9

First download a very generic macro %UT_VARLIST  (ut_varlist.sas) 

See https://communities.sas.com/t5/SAS-Programming/Macro-function-to-return-a-list-of-variables-in-a-tab...

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;

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

Diskussionsstatistiken
  • 13 Antworten
  • 5895 Aufrufe
  • 0 Kudos
  • 7 in Unterhaltung