M. Stein.
M. Stein.

Reputation: 13

Using a series of values for a SAS macro parameter

I'm looking for a way to use a series of values for a macro parameter instead of a single value. I'm basically manipulating a series of files for consecutive months (May 2014 to Sept 2015) and I've written a macro to take advantage of the naming conventions. However, I'm still manually writing out the months to use the macro. I'm doing this many times over with lots of different files from this month. Is there a way to have the parameter reference a list of values and go through them like an array/do-loop? I've looked into %ARRAY as a possibility but that doesn't seem to do what I'm looking for unless I'm not seeing it's full capability. I've attached a sample of this code below.

%MACRO memmonth(monyr=);
proc freq data=work.both_&monyr ;
    table var1/ out=work.mem_&monyr;
run;
data work.mem_&monyr;
    set work.mem_&monyr;
    count_&monyr=count;
run;

%MEND memmonth;


%memmonth(monyr=may14)
%memmonth(monyr=jun14)
%memmonth(monyr=jul14)
%memmonth(monyr=aug14)
%memmonth(monyr=sep14)
%memmonth(monyr=oct14)
%memmonth(monyr=nov14)
%memmonth(monyr=dec14)
%memmonth(monyr=jan15)
%memmonth(monyr=feb15)
%memmonth(monyr=mar15)
%memmonth(monyr=apr15)
%memmonth(monyr=may15)
%memmonth(monyr=jun15)
%memmonth(monyr=jul15)
%memmonth(monyr=aug15)
%memmonth(monyr=sep15)

Upvotes: 1

Views: 73

Answers (1)

Tom
Tom

Reputation: 51566

In general I would recommend passing the list of values as a space delimited list and adding looping logic in the macro. If spaces are valid characters in the values then use some other delimiter. Do not use comma as the delimiter as it means you will need to use macro quoting to call the macro.

So your basic macro is this.

%macro memmonth(monyr);
proc freq data=work.both_&monyr ;
  table var1/ out=work.mem_&monyr (rename=(count=count_&monyr)) ;
run;
%mend memmonth;
%memmonth(may14)
%memmonth(jun14)

You could change it to this.

%macro memmonth(monyrlist);
%local i monyr;
%do i=1 %to %sysfunc(countw(&monyrlist));
  %let monyr=%scan(&monyrlist,&i);
  proc freq data=work.both_&monyr ;
    table var1/ out=work.mem_&monyr (rename=(count=count_&monyr)) ;
  run;
%end;
%mend memmonth;
%memmonth(may14 jun14)

If you always want to process all of the months in an interval then you could just pass in the start and end month of the interval.

%macro memmonth(start,end);
%local i monyr;
%do i=0 %to %sysfunc(intck(month,"01&start"d,"01&end"d));
  %let monyr=%sysfunc(intnx(month,"01&start"d,&i),monyy5.);
  proc freq data=work.both_&monyr ;
    table var1/ out=work.mem_&monyr (rename=(count=count_&monyr)) ;
  run;
%end;
%mend memmonth;
%memmonth(may14,sep15)

If you have a source list, whether it is a text file or a dataset, you can use a simple data step to generate macro calls. So if you have an input dataset with the variable MONYR then your driver program would look like this:

data _null_;
   set mylist ;
   call execute(cats('%nrstr(memmonth)(',MONYR,')'));
run;

If the source is a file with the names then replace the SET statement with the appropriate INFILE and INPUT statements. If the source is a directory name then look at one of the many SAS ways to read the names of files in a directory into a dataset and use that to drive the macro call generation.

Upvotes: 1

Related Questions