Macro Variables

The SAS Macro language enables you to write programs that generate SAS code, which is then submitted to the SAS interpreter for execution. A macro can be as simple as text substitution, creating a short placeholder for a long string of code, or a macro can generate SAS code dynamically, generating different code depending upon some input.

We will want to distinguish between macro variables, which are simple placeholders, and macros, which are usually code-generating.

Macro Variables and %LET

Working with macro variables is a two-part process. First you assign a value to a macro variable - this value will be some string of text. Then you use the macro variable to substitute that text into some block of SAS code. This is called macro resolution.

Although macro values are text, you typically do not use quotes in defining them - if you do, the quotes are included when the text is substituted.

A macro value will typically be a token, a token fragment, or a collection of tokens. To make a macro value include more than one SAS statement requires the use of macro functions, and this is more typically done as a macro than as a macro variable. Where the value is a token fragment to be combined with a suffix, the macro variable is called with a leading ampersand and a trailing period.

A macro value may be hard-coded as a constant, but it can also be defined as the result of macro functions. Whatever is on the right-hand side of the equals sign in a %LET statement is evaluated before the assignment is made.

Note that when you create a macro variable, you give it a SAS name following the same rules you use for variable names within data sets (no spaces, no special characters, capitalization does not matter). When you go to use the macro variable, the name is always prefixed by an ampersand, "&".

In the following example, we just illustrate with two marital status variables (different years). Imagine how much output would be produced if we used the full list.

* Assigning values to macro variables;
%let dsn = y.nlswomen;
%let mstatus = R0002400 R0133700 /*R0205100 R0288200 
    R0308300 R0367600 R0455600 R0491300 R0661400 R0666600 R0721700 
    R0869900 R0997700 R1290700 R1664710 R3507200 R4278200 
    R5447500 R6516200*/;

* Using the macro variables;
proc freq data=&dsn;
    tables &mstatus / nocum;
run;
                            The FREQ Procedure

                                MAR_STAT, 67
 
                            R0002400    Frequency     Percent
              -----------------------------------------------
              MARRIED SPOUSE PRESENT        4064       79.95 
              MARRIED SPOUSE ABSENT           46        0.90 
              WIDOWED                        145        2.85 
              DIVORCED                       253        4.98 
              SEPARATED                      285        5.61 
              NEVER MARRIED                  290        5.71 

                                MAR_STAT, 71
 
                            R0133700    Frequency     Percent
              -----------------------------------------------
              MARRIED SPOUSE PRESENT        3568       77.72 
              MARRIED SPOUSE ABSENT           27        0.59 
              WIDOWED                        206        4.49 
              DIVORCED                       285        6.21 
              SEPARATED                      282        6.14 
              NEVER MARRIED                  223        4.86 

                          Frequency Missing = 492

By default the code that is echoed in the log is just what you send to the macro interpreter. If you want to see what the code looks like after macro variable substitution, you need to invoke the SAS option SYMBOLGEN. In much of the SAS documentation, macro variables are called "symbols" and lists of macro variables are called "symbol tables". Your log will look like this:

%let dsn = y.nlswomen;
%let mstatus = R0002400 R0133700 ;

options symbolgen;
proc freq data=&dsn;
    tables &mstatus / nocum;
run;

Notice the echo of PROC FREQ includes notes on the macro values used.

2          %let dsn = y.nlswomen;
3          %let mstatus = R0002400 R0133700 ;
4          
5          options symbolgen;
6          proc freq data=&dsn;
SYMBOLGEN:  Macro variable DSN resolves to y.nlswomen
7           
SYMBOLGEN:  Macro variable MSTATUS resolves to R0002400 R0133700
7        !  tables &mstatus / nocum;
8          run;

NOTE: There were 5083 observations read from the data set Y.NLSWOMEN.
NOTE: The PROCEDURE FREQ printed page 1.
NOTE: PROCEDURE FREQ used (Total process time):
      real time           0.01 seconds
      cpu time            0.00 seconds
      
                            The FREQ Procedure

                                MAR_STAT, 67
 
                            R0002400    Frequency     Percent
              -----------------------------------------------
              MARRIED SPOUSE PRESENT        4064       79.95 
              MARRIED SPOUSE ABSENT           46        0.90 
              WIDOWED                        145        2.85 
              DIVORCED                       253        4.98 
              SEPARATED                      285        5.61 
              NEVER MARRIED                  290        5.71 

                                MAR_STAT, 71
 
                            R0133700    Frequency     Percent
              -----------------------------------------------
              MARRIED SPOUSE PRESENT        3568       77.72 
              MARRIED SPOUSE ABSENT           27        0.59 
              WIDOWED                        206        4.49 
              DIVORCED                       285        6.21 
              SEPARATED                      282        6.14 
              NEVER MARRIED                  223        4.86 

                          Frequency Missing = 492

More examples:

2          %let test = TEXT;
3          %put test=&test;
test=TEXT
4          
5          %let test = "TEXT";
6          %put test=&test;

If a macro variable contains a semi-colon, use the macro function %quote.

%LET test = %quote(proc print; run;);

data class; 
  set sashelp.class;
run;
&test;
             Obs    Name       Sex    Age    Height    Weight

               1    Alfred      M      14     69.0      112.5
               2    Alice       F      13     56.5       84.0
               3    Barbara     F      13     65.3       98.0
               4    Carol       F      14     62.8      102.5
               5    Henry       M      14     63.5      102.5
               6    James       M      12     57.3       83.0
               7    Jane        F      12     59.8       84.5
               8    Janet       F      15     62.5      112.5
               9    Jeffrey     M      13     62.5       84.0
              10    John        M      12     59.0       99.5
              11    Joyce       F      11     51.3       50.5
              12    Judy        F      14     64.3       90.0
              13    Louise      F      12     56.3       77.0
              14    Mary        F      15     66.5      112.0
              15    Philip      M      16     72.0      150.0
              16    Robert      M      12     64.8      128.0
              17    Ronald      M      15     67.0      133.0
              18    Thomas      M      11     57.5       85.0
              19    William     M      15     66.5      112.0

Additional Reading