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-createsval1,val2, ... — one per row.&sqlobsis the number of rows the query returned.&&val&iresolves in two passes:&&→&,&i→1, then&val1→F.%localkeeps 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.