Dynamic SAS Macro programs hinge on the ability to tell how many variables exist within a given SAS Dataset. The majority of solutions that exist to solve this dilemma rely on the combination of NULL DATA steps, SET statement with OBS=, and arrays or some creative proc sql using SAS dictionary.tables. Both of these options are discussed at the end of the article due to the overall lack of implementation appeal as they require using procedural code and creating a global sas macro variable that is context dependent. Thus, there must be a better way right?
The introduction of %sysfunc function enabled the macro processor to access most data step functions and several SAS Component Language (SCL) functions allowing for nvars to easily be extracted using a SAS Macro Function. Therefore, the ability to avoid the implementation issues that arose before is now a reality. The idealized approach would be to harness the macro ability to provide on-demand variable counts. Hence, the creation of the following macro function:
/**
* Obtains variable count from a Dataset.
*
* @param dsn Dataset Name to retrieve variable information from.
* @return nvars Number of Variables in Dataset.
**/
%macro nvars(dsn);
%let dataset=&dsn;
%let dsid = %sysfunc(open(&dataset));
%if &dsid %then %do;
%let nvars=%sysfunc(attrn(&dsid,NVARS));
%let rc = %sysfunc(close(&dsid));
%end;
%else
%put Open for data set &dsn failed - %sysfunc(sysmsg());
&nvars
%mend nvars;
/* Direct Call **/
%put Number of Variables: %nvars(sasuser.class);
/* Or storing to variable **/
%let nvars_class = %nvars(sasuser.class);
%put Number of Variables: &nvars_class;
What’s unique about this particular macro function is that it mimicks a traditional function in the sense that the total number of variables is returned upon call. Structuring the macro function in this manner enables the preservation of the result while enabling on-demand calls.
As promised, here are previous implementations that were required to access the number of variables in the dataset. These methods of finding the count of variables in a SAS Dataset are still valid, just not necessarily ideal.
Getting Variables using Arrays
data _null_;
if 0 then do;
set sashelp.class (obs=0);
end;
/* Build arrays using variable TYPE id to split between numeric and character */
array chars _character_;
array nums _numeric_;
/* Figure out the amount being held in each array */
ncharvar = dim(chars);
nnumvar = dim(nums);
/* Add together for total amount of variables */
nvar = ncharvar + nnumvar;
put nvar=;
run;
Using SAS DICTIONARY.TABLES
/* Null Dataset Method */
data _null_;
set DICTIONARY.TABLES;
/* Restrict information to specified dataset in library */
where libname = "SASHELP" and memname="CLASS";
/* Get variable count */
put nvar=;
run;
/* Proc SQL Method */
proc sql noprint;
/* Select Number of Variables and place it into a global sas macro variable*/
select nvar into :nvar
from DICTIONARY.TABLES
/* Specifies the selection of data set */
where libname = "SASHELP" and memname="CLASS";
quit;
%put nvar=&nvar;