SAS Macros

The SAS Macro language is designed to generate SAS commands that otherwise would have to be typed. It is useful when a block of commands must be run repeatedly with a few minor changes for each run. We've seen a very simple example of a macro variable in one of the lab exercises.

  %let name=HAWTHORNE, NATHANIEL;

      ...

  title "&name: Lab 1 Part a";
      ...

  title "&name: Lab 1 Partb";

This somewhat contrived example illustrates two features of the SAS Macro language. Assignment statements begin with the %let command, and macro variables are referenced with a leading & such as &name. When SAS sees this reference to a macro variable, it "expands" the variable to its value. So what gets printed in the title instead of &name is HAWTHORNE, NATHANIEL.

The %macro statement marks the beginining of a macro definition. It ends with the %mend statement. A macro definition creates a function which can be run by entering its name and any arguments established by its definition. An interesting example might be to automate the appending of quizzes and tests to the master gradebook --


 * addtest.sas: Define a macro to add a quiz, test, lab score, etc.
   to the master gradebook *;

  %macro addtest(tests_quizzes, append=);
    proc copy in=econ100 out=work; select gbook; run;

    %let i=1; %let tq = %scan(&tests_quizzes, &i);

    %do %while( %quote(&tq) ^= %quote() );
      data &tq;
        length name2 $25 username $9;
        infile "&tq..data" lrecl=60 pad;
        input name2    $ 9-27
              username $ 30-37
              &tq;
      run;
      proc sort data=&tq; by username; run;

      data gbook(drop=name2);
        update gbook &tq;
        by username;
        if name="" then name=name2;
      run;

      %let i = %eval(&i+1);
      %let tq = %scan(&tests_quizzes, &i);
    %end;
    %if %quote(&append) = %quote() %then %do;
      proc print data=gbook; id name username;
        var &tests_quizzes;
      run;
    %end;

    %else %do;
      proc copy in=work out=econ100; select gbook; run;
      proc print data=econ100.gbook; id name username;
        var &tests_quizzes;
      run;
    %end;
  %mend addtest;

 *%addtest(quiz1 quiz2 quiz3);

This example adds as many quizzes, tests, labs, whatever as you list in the first argument to the macro and prints the combination at the end.

The macro definiton begins with %macro addtest(tests_quizzes, append=);. The name of the macro is established to be addtest (which is a bit of a misnomer since it can be used to add any type of evaluation). The macro has one "positional" argument named tests_quizzes. It is a required argument. The second argument is a "key-word" argument and is an optional argument. The end of the macro is indicated by the %mend addtest; statement.

The macro "invocation" is performed by %addtest(quiz1 quiz2 quiz3);. This statement runs the macro with three tests as the input argument. Macro arguments are separated by commas, so this list is all one argument. The macro performs the append operation for each of the three quizzes and prints the final result at the end.

The optional key-word argument is not given, so its value is null. The %if %quote(&append) ^= %quote() %then %do; at the end of the macro evaluates to false, so the temporary gbook dataset is not copied to the permanent version. The idea here is check the result for accuracy before overwriting the permanent master gradebook. When it all is correct, rerun the macro with the append parameter set to a nonnull value, for example --


  %addtest(quiz1 quiz2 quiz3, append=yes);