I will answer the main question that Bambi asked in the comments:
My main task here is how to return a value from a macro.
I'm going to argue with Dirk here in an important way. He says:
SAS macro inserts code. It will never be able to return a value, although in some cases you can mimic functions
I do not agree. The SAS macro returns the text inserted into the workflow. Returns is an absolutely suitable term for this. And when the text turns out to be a single number, we can say that it returns a value.
However, a macro can only return one value if it has only macro operators in addition to that value. That is, each line should begin with % . Anything that does not start with % will be returned (and some things that start with % can also be returned).
Therefore, the important question is: how can I return only the value from the macro.
In some cases, such as this one, this is only possible with macro codes. In fact, in many cases this is technically possible - although in many cases it is more than necessary.
A related article by Jack Hamilton includes an example that is relevant here. He rejects this example, but mainly because his article is devoted to counting cases in cases where NOBS is incorrect - either with the WHERE clause or in some other cases when the data sets were changed without updating the NOBS metadata.
In your case, you seem to be completely happy to trust NOBS - this example will do.
A macro that returns a value must have exactly one statement, which is either not a macro syntax operator or a macro syntax operator that returns a value to the processing flow. %sysfunc is an example of a statement that does this. Things like %let , %put , %if , etc., are syntax operators that return nothing (by themselves); so that you can have as much as you want.
You should also have one statement that puts the value in the processing flow: otherwise you will not get anything from your macro at all.
Here is a stripped down version of Jack's macro at the end of page 3, simplified to remove nlobsf :
%macro check; %let dsid = %sysfunc(open(sashelp.class, IS)); %if &DSID = 0 %then %put %sysfunc(sysmsg()); %let nlobs = %sysfunc(attrn(&dsid, NLOBS)); %put &nlobs; %let rc = %sysfunc(close(&dsid)); %mend;
This macro is not a function style macro. It does not return anything to the processing thread! This is useful for viewing a log, but not useful for getting a value with which you can program. However, this is a good start for function style macro, because you really want this &nlobs , right?
%macro check; %let dsid = %sysfunc(open(sashelp.class, IS)); %if &DSID = 0 %then %put %sysfunc(sysmsg()); %let nlobs = %sysfunc(attrn(&dsid, NLOBS)); &nlobs %let rc = %sysfunc(close(&dsid)); %mend;
Now this is a function style macro: it has one statement that is not a macro syntax operator, &nlobs. on a simple line all by itself.
This is actually more than just a statement; Remember how I said that %sysfunc returns a value to the processing thread? You can remove the %let part of this statement, leaving you with
%sysfunc(attrn(&dsid, NLOBS))
And then the value will be placed directly in the processing flow itself, which allows you to use it directly. Of course, it's not so easy to debug if something goes wrong, but I'm sure you can get around this if you need to. Also pay attention to the absence of a semicolon at the end of the statement - this is because semicolons are not required to perform macro functions, and we do not want to return extra semicolons.
Let's behave ourselves, add a few %local to get it nice and safe, and make the name of the data set a parameter, because nature does not tolerate a macro without parameters:
%macro check(dsetname=); %local dsid nlobs rc; %let dsid = %sysfunc(open(&dsetname., IS)); %if &DSID = 0 %then %put %sysfunc(sysmsg()); %let nlobs = %sysfunc(attrn(&dsid, NLOBS)); &nlobs %let rc = %sysfunc(close(&dsid)); %mend; %let classobs= %check(dsetname=sashelp.class); %put &=classobs;
There you have it: a function style macro that uses the nlobs function to find out how many rows there are in a particular data set.