Skip to content
AgileLogics
7 min read

Macro Programs

Prerequisites: Macro variables

A macro is a named, parameterized block of code — a template SAS fills in and runs each time you call it.

Defining and calling

%macro summarize(data=, var=);
   proc means data=&data n mean maxdec=1;
      var &var;
   run;
%mend summarize;

%summarize(data=sashelp.class, var=age)
      The MEANS Procedure

   Analysis Variable : Age

    N          Mean
-------------------
   19          13.3
-------------------
  • %macro name(params); ... %mend; defines it. Keyword parameters (data=) can have defaults: %macro summarize(data=, var=, dec=1);.
  • Call it with %name(...) — no semicolon needed, since the macro generates complete statements.
  • Parameters are local macro variables inside the macro.

Seeing the generated code

options mprint;
%summarize(data=sashelp.class, var=height)

Log (abridged):

MPRINT(SUMMARIZE):   proc means data=sashelp.class n mean maxdec=1;
MPRINT(SUMMARIZE):   var height;
MPRINT(SUMMARIZE):   run;

MPRINT shows the SAS code each macro produced — turn it on whenever you debug macros. MLOGIC traces %IF and %DO decisions, and SYMBOLGEN shows each variable resolution.

Conditions and loops

%IF and %DO decide which code is generated — they don't process data rows (that's what DATA step IF and DO are for):

%macro size(n);
   %if &n > 10 %then %put &n is big;
   %else %put &n is small;
%mend size;

%size(5)
%size(50)

%macro years(start, stop);
   %do y = &start %to &stop;
      %put Processing year &y;
   %end;
%mend years;

%years(2022, 2024)
5 is small
50 is big
Processing year 2022
Processing year 2023
Processing year 2024

%IF compares with integer arithmetic when both sides look like whole numbers, and as text otherwise.

A data-driven macro

Run one report per value, without typing the list:

%macro by_sex_report;
   %local i n val;
   proc sql noprint;
      select distinct sex into :val1- from sashelp.class;
   quit;
   %let n = &sqlobs;
   %do i = 1 %to &n;
      %let val = &&val&i;
      title "Students of sex &val";
      proc print data=sashelp.class noobs;
         where sex = "&val";
         var name age;
      run;
   %end;
   title;
%mend by_sex_report;

%by_sex_report
  • into :val1- creates val1, val2, ... — one per row.
  • &sqlobs is the number of rows the query returned.
  • &&val&i resolves in two passes: && → &, &i → 1, then &val1 → F.
  • %local keeps the macro's variables from overwriting global ones with the same names.

When not to use a macro

If a BY statement, a CLASS statement, or a format can do the job, use it — it's simpler and faster than generating many steps. Macros shine for repeated program structure: the same steps for many data sets, dates, or output files.