Data _null_;
*i=1;
if i = 0 then set &ds. nobs= mycount;
Call symput('mycount', mycount);
Run;
The "mycount" macro variable keeps the dataset row count.
How to put these lines into a macro which returns the dataset row count?!
%macro ds_rowct(ds);
....
%mend;
I would prefer to use this :
%macro ds_rowct(ds);
%let dsid=%sysfunc(open(&ds.));
%let nobs=%sysfunc(attrn(&dsid.,nlobs));
%let dsid=%sysfunc(close(&dsid.));
%put &ds. have &nobs. obs.;
%mend;
%ds_rowct(sashelp.class)
1 %macro ds_rowct(ds); 2 %let dsid=%sysfunc(open(&ds.)); 3 %let nobs=%sysfunc(attrn(&dsid.,nlobs)); 4 %let dsid=%sysfunc(close(&dsid.)); 5 6 %put &ds. have &nobs. obs.; 7 %mend; 8 9 10 11 %ds_rowct(sashelp.class) sashelp.class have 19 obs.
Macros do not normally "return" anything. The just generate SAS code for SAS to execute.
So the simplest way to have it "return" something is to TELL it WHERE to put what you want.
%macro ds_rowct(ds,mvar=mycount);
%if not %symexist(&mvar) %then %global &mvar;
data _null_;
call symputx("&mvar",mycount);
stop;
set &ds. nobs=mycount;
run;
%mend;
Example:
82 %ds_rowct(sashelp.class)
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
83 %put &=mycount;
MYCOUNT=19
PS: You almost never want to use the ancient CALL SYMPUT() method. The CALL SYMPUTX() method replaced it decades ago. The only time you would want CALL SYMPUT() is when you need the macro variable's value to have leading or trailing spaces.
Thanks,
If mvar pre-exists, I assume still work. But anyway, no additional macro variable?!
Macro does not return anything. But much more convenient to "Take" that way , say,
%if %ds_rowct(&dsname.) %then %do;
....
%end;
If not, simply invoke the macro and then evaluate the speific macro variable, BUT
the reality is that too hard to remember all the variables when you are coding with
dozens of macros!!!
@hellohere wrote:
Thanks,
If mvar pre-exists, I assume still work. But anyway, no additional macro variable?!
Macro does not return anything. But much more convenient to "Take" that way , say,
%if %ds_rowct(&dsname.) %then %do;
....
%end;
If not, simply invoke the macro and then evaluate the speific macro variable, BUT
the reality is that too hard to remember all the variables when you are coding with
dozens of macros!!!
You can create macros that only emit PART of a statement. Then you could use the macro as if it was a function, like in your new example. Note that your original question did not state that was your objective.
There are dozens of examples of macros that do that for the example problem of finding the number of observations in a dataset. See for example this one:
https://github.com/sasutils/macros/blob/master/nobs.sas
%if 0<%nobs(&dsname.,mvar=) %then %do;
I would prefer to use this :
%macro ds_rowct(ds);
%let dsid=%sysfunc(open(&ds.));
%let nobs=%sysfunc(attrn(&dsid.,nlobs));
%let dsid=%sysfunc(close(&dsid.));
%put &ds. have &nobs. obs.;
%mend;
%ds_rowct(sashelp.class)
1 %macro ds_rowct(ds); 2 %let dsid=%sysfunc(open(&ds.)); 3 %let nobs=%sysfunc(attrn(&dsid.,nlobs)); 4 %let dsid=%sysfunc(close(&dsid.)); 5 6 %put &ds. have &nobs. obs.; 7 %mend; 8 9 10 11 %ds_rowct(sashelp.class) sashelp.class have 19 obs.
Dive into keynotes, announcements and breakthroughs on demand.
Explore Now →Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.