- by Handson
- October 31, 2025
SAS Macro Tutorial: Step-by-Step Guide with Examples, Functions, and Best Practices
SAS Macro Tutorial — From Zero to Confident
1) Why the Macro Facility?
-
What it is: A text substitution and code-generation system that runs before SAS compiles/executes DATA/PROC steps.
-
What it’s for: Reuse, parameterization, looping/branching to generate SAS code dynamically.
2) Macro Variables
2.1 Create & Use
%let lib=work;
%let ds=sales2025;
proc print data=&lib..&ds(obs=5); run;
2.2 Automatic Macro Variables
Examples: &sysdate9, &systime, &sysuserid, &sysver, &syslast
%put NOTE: Today is &sysdate9 &systime., SAS &sysver, last=&syslast;
2.3 Create in DATA/PROC
data _null_;
call symputx('nobs', 123);
run;
%put &=nobs;
From PROC SQL:
proc sql noprint;
select count(*) into :nrows trimmed from sashelp.class;
quit;
%put &=nrows;
3) Macro Programs
3.1 Define/Call
%macro topN(lib=work, ds=, n=10);
%if %superq(ds)= %then %do;
%put ERROR: ds= is required.;
%return;
%end;
proc sort data=&lib..&ds out=_tmp; by descending _all_; run;
proc print data=_tmp(obs=&n); title "Top &n from &lib..&ds"; run;
%mend;
%topN(ds=sashelp.class, n=5)
3.2 Parameters
-
Positional or Named (with defaults)
-
Use
%superq()to test safely.
3.3 Scope
%let g=global;
%macro scope();
%local g;
%let g=local;
%put INSIDE: &=g;
%mend;
%scope()
%put OUTSIDE: &=g;
4) Macro Logic & Loops
IF/ELSE
%macro rpt(type=summary);
%if &type=summary %then %do;
proc means data=sashelp.class; run;
%end;
%else %if &type=detail %then %do;
proc print data=sashelp.class; run;
%end;
%mend;
DO Loop
%macro repeat(n=3);
%do i=1 %to &n;
%put Iter &i;
%end;
%mend;
%repeat(n=5)
5) Macro Functions
-
%upcase(),%substr(),%scan() -
%eval()vs%sysevalf() -
%sysfunc()to call DATA step functions
%let today=%sysfunc(today(), date9.);
%put &today;
6) Quoting
%let val=Tom & Jerry;
%put BAD: &val;
%put GOOD: %superq(val);
7) Dynamic Code Generation
Loop over values
%let months=JAN FEB MAR;
%macro run3;
%do i=1 %to %sysfunc(countw(&months));
%let word=%scan(&months,&i);
proc sql; create table out_&word as
select * from mylib.txn_&word; quit;
%end;
%mend; %run3
Loop over datasets
proc sql noprint;
select memname into :dsets separated by ' '
from dictionary.tables
where libname='SASHELP' and memtype='DATA' and upcase(memname) like 'C%';
quit;
%macro printAll;
%do i=1 %to %sysfunc(countw(&dsets));
%let ds=%scan(&dsets,&i);
proc print data=sashelp.&ds(obs=5); title "&ds"; run;
%end;
%mend; %printAll
8) Passing Data Values into Macros
DATA Step → Macro Var
data _null_;
set sashelp.class end=last;
retain list '';
list=cats(list, ifc(list='','',','), name);
if last then call symputx('names', list);
run;
%put &=names;
PROC SQL INTO
proc sql noprint;
select name into :names separated by ' ' from sashelp.class;
quit;
%put &=names;
9) Debugging
options mprint mlogic symbolgen;
-
MPRINT shows generated code.
-
SYMBOLGEN shows macro var resolutions.
-
MLOGIC shows macro flow.
10) Autocall Libraries
options mautosource sasautos=(sasautos "C:macros");
11) Best Practices
-
Use
%superq()for safe checks. -
Keep macros parameterized with defaults.
-
Debug with MPRINT/MLOGIC.
12) Worked Examples
Import CSVs
%macro import_csvs(path=, outlib=work, ext=csv);
%local rc did mem i n f;
%let rc=%sysfunc(filename(fref,"&path"));
%let did=%sysfunc(dopen(&fref));
%if &did=0 %then %do; %put ERROR: Cannot open &path; %return; %end;
%let n=%sysfunc(dnum(&did));
%do i=1 %to &n;
%let f=%sysfunc(dread(&did,&i));
%if %upcase(%scan(&f,-1,.))=%upcase(&ext) %then %do;
%let mem=%scan(&f,1,.);
proc import datafile="&path/&f" dbms=csv out=&outlib..&mem replace; guessingrows=max; run;
%end;
%end;
%mend;
Yearly Report
%macro yearly_report(start=2021, stop=2025);
%do y=&start %to &stop;
proc sql;
create table yr&y as
select "&y"d as year format=year4., *
from sales.txn_&y;
quit;
%end;
data all_years; set %do y=&start %to &stop; yr&y %end;; run;
proc means data=all_years n mean sum; class year; var amount; run;
%mend;
13) Interview Concepts
-
Macro executes before DATA/PROC compile.
-
%evalvs%sysevalf. -
Macro quoting prevents premature resolution.
-
Use
SYMPUTXoverSYMPUT. -
%sysfuncbridges data step functions.
14) Exercises
-
Build
%freq(lib=, ds=, var=, where=). -
Multi-export macro for datasets.
-
Dynamic WHERE clause with name list.
15) Cheat Sheet
%let x=1; &x
%if &x>0 %then %do; ... %end;
%do i=1 %to 10; ... %end;
%eval(2+3) %sysevalf(3.14*2)
%sysfunc(today(),date9.)
%superq(name)
options mprint mlogic symbolgen;


