Macros with Parameters

SAS macro programs not only add conditional execution of SAS statements and looping to your global SAS code (not just DATA steps), but also the ability to set variable parameters when you call the macro.

In this example: We often want to merge group summary statistics back on to the original data set. I start with the example of merging group means, then generalize.

We also recommend a workflow for creating macros:

  • Write a complete example of one thing your macro should accomplish.
  • Convert elements of your macro into macro variables, and test.

Step 1: Write & debug an example

We’ll start with an example that calculates the groupwise mean income in 1967, by marital status.

options symbolgen mprint=off;
proc means data=y.nlswages noprint; 
    class R0002400;
    types R0002400;
    var R0043600;
    output out=mean mean=R0043600mean;
    run;

proc sort data=y.nlswages out=sorted;
    by R0002400;
    run;

data nlswages;
    merge sorted mean;
    by R0002400;
    label R0043600mean="mean of 67 income"; *otherwise mean inherits its label;
    format R0043600mean ; *otherwise it inherits a format, too;
    run;

proc print data=nlswages(obs=5);
var R0002400 R0043600 R0043600mean;
run;
        Obs           R0002400            R0043600      R0043600mean

          1    MARRIED SPOUSE PRESENT    5000-5999         1264.55  
          2    MARRIED SPOUSE PRESENT              B       1264.55  
          3    MARRIED SPOUSE PRESENT    0                 1264.55  
          4    MARRIED SPOUSE PRESENT    1-999             1264.55  
          5    MARRIED SPOUSE PRESENT    2000-2999         1264.55  

Step 2: Convert to macro variables

Here we will generalize out example to cover other

  • data set names
  • variable names
  • grouping variables
  • statistics
%macro mergestat(dsn, var, group, stat);
proc means data=&dsn noprint;
    class &group;
    types &group;
    var &var;
    output out=&stat &stat=&var&stat;
    run;

proc sort data=&dsn out=sorted;
    by &group;
    run;

data &dsn;
    merge sorted &stat;
    by &group;
    label &var&stat="&stat of &var";
    format &var&stat ;
    run;

%mend mergestat;

Then, two examples of using the macro

proc copy in=y out=work;
  select nlswages;
run;

*options mprint=on;
%mergestat(nlswages, R6204300, R0002400, mean);
proc print data=nlswages(obs=5);
  var R0002400 R6204300 R6204300mean;
run;
         Obs           R0002400           R6204300    R6204300mean

           1    MARRIED SPOUSE PRESENT       B          12718.90  
           2    MARRIED SPOUSE PRESENT       B          12718.90  
           3    MARRIED SPOUSE PRESENT       A          12718.90  
           4    MARRIED SPOUSE PRESENT       D          12718.90  
           5    MARRIED SPOUSE PRESENT       A          12718.90  
proc copy in=y out=work;
  select nlswages;
run;

%mergestat(nlswages, R7312300, R0002400, median);
proc print data=nlswages(obs=5);
  var R0002400 R7312300 R7312300median;
run;
     Obs           R0002400              R7312300       R7312300median

       1    MARRIED SPOUSE PRESENT    03000-03999            8000     
       2    MARRIED SPOUSE PRESENT                 A         8000     
       3    MARRIED SPOUSE PRESENT                 A         8000     
       4    MARRIED SPOUSE PRESENT                 D         8000     
       5    MARRIED SPOUSE PRESENT                 A         8000     

Nested Macros

In this example, we not only want to merge group summary stats, but we also want to score the original variable as greater than or less than that stat.;

From this (our first example, above):

data nlswages;
    set nlswages;
    R0043600cat=(R0043600>R0043600mean);
    run;

proc freq;
    tables R0043600cat;
    run;

To this:

%macro aboveaverage(dsn, var, stat);
data &dsn;
    set &dsn;
    &var.cat=(&var>&var&stat);
    run;
%mend aboveaverage;

It should be pretty obvious that this macro requires something like %mergestat first, which leads to the next example:

%macro maa(dsn, var, group, stat);
    %mergestat(&dsn, &var, &group, &stat);
    %aboveaverage(&dsn, &var, &stat)
%mend maa;

An example in use

proc copy in=y out=work;
  select nlswages;
run;

%maa(nlswages, R6204300, R0002400, mean);

proc freq;
    tables R6204300cat / nocum;
    run;
                            The FREQ Procedure

                   R6204300cat    Frequency     Percent
                   ------------------------------------
                             0        4954       97.46 
                             1         129        2.54 

And another:

proc copy in=y out=work;
  select nlswages;
run;

%maa(nlswages, R7312300, R0002400, median);

proc freq;
    tables R7312300cat / nocum;
    run;
                            The FREQ Procedure

                   R7312300cat    Frequency     Percent
                   ------------------------------------
                             0        4963       97.64 
                             1         120        2.36