6.5 Simplifying Programs with Macro Variables (%LET)
Key Takeaways
%LET creates a macro variable whose value is always stored as text, with leading and trailing blanks stripped and any quotation marks kept literally.
An ampersand reference such as ®ion substitutes the stored text into the program before the DATA or PROC step compiles.
Macro variables resolve inside double quotation marks but never inside single quotation marks.
The macro variable name delimiter is a period: &prefix.2026 resolves the variable named prefix and the delimiting period is consumed rather than printed.
OPTIONS SYMBOLGEN and the %PUT statement expose what a macro variable actually resolved to, which is the fastest way to diagnose an unresolved reference.
6.5 Simplifying Programs with Macro Variables (%LET)
Quick Answer: The content guide requires you to "use macro variables to simplify program maintenance" through three expanded objectives: create macro variables with the
%LETstatement, use macro variables within SAS programs, and use the macro variable name dot delimiter (.). Base-level macro work is text substitution and nothing more — no%MACROdefinitions are required for A00-231.
A macro variable holds text. Before SAS compiles a DATA or PROC step, the macro processor scans the source, finds every &name reference, and replaces it with the stored text. The DATA step never knows a macro variable existed; it sees only the substituted result.
1. Creating Macro Variables with %LET
%LET macro-variable-name = value;
%let reportYear = 2026;
%let region = West;
%let inLib = sasuser;
Four rules govern what actually gets stored:
- Everything is text.
%let reportYear = 2026;stores the four characters2026, not the number two thousand twenty-six. SAS treats the substituted text as a number only when the surrounding SAS code puts it in a numeric context. - Leading and trailing blanks are stripped.
%let region = West ;storesWest. - Quotation marks are stored literally.
%let region = 'West';stores'West'including the quotes, which then appear in the substituted code — a classic source of doubled quotation marks. - The name follows SAS naming rules — 1 to 32 characters, beginning with a letter or underscore.
/* One edit changes the whole program */
%let region = West;
data work.filtered;
set sashelp.shoes;
where Region = "®ion"; /* becomes: where Region = "West" */
run;
proc means data=work.filtered mean sum;
var Sales;
title "Sales Summary for ®ion";
run;
Change the %LET to Africa and every downstream reference follows. That is precisely the "simplify program maintenance" the objective is describing.
2. Referencing Macro Variables: the Quotation Mark Rule
The macro processor scans double-quoted strings but skips single-quoted strings entirely.
| Code | Result |
|---|---|
title "Report for ®ion"; | Report for West — resolved |
title 'Report for ®ion'; | Report for ®ion — literal text |
where Region = "®ion"; | where Region = "West" — correct |
where Region = '®ion'; | Compares Region to the literal string ®ion, matching nothing |
Exam Trap: this is the most-tested macro fact at Base level. Whenever a macro reference must resolve inside a quoted string — a
TITLE, aFOOTNOTE, aWHEREclause, a file path — the string must use double quotation marks.
3. The Name Delimiter: The Period
A macro variable reference ends at the first character that cannot be part of a SAS name. That works for ®ion/sales, but it fails when text must butt directly against the value:
%let prefix = sales;
/* WRONG: SAS looks for a macro variable named PREFIX2026 */
data &prefix2026; /* WARNING: Apparent symbolic reference PREFIX2026 not resolved */
run;
/* RIGHT: the period terminates the name and is then consumed */
data &prefix.2026; /* resolves to: data sales2026; */
run;
The delimiting period is removed during resolution. When the generated text needs a period of its own, code two periods:
%let lib = sasuser;
%let ds = clients;
proc print data=&lib..&ds; /* resolves to: proc print data=sasuser.clients */
run;
The first period ends &lib; the second survives as the two-level-name separator. Writing &lib.&ds produces the single token sasuserclients and an error.
%let yr = 2026;
%let ext = csv;
/* One delimiter period plus one literal period in a file name */
filename out "C:\reports\summary_&yr..&ext"; /* summary_2026.csv */
4. Automatic Macro Variables
SAS maintains a set of read-only macro variables that resolve without any %LET:
| Variable | Contains | Example |
|---|---|---|
&SYSDATE | Session start date, DATE7. | 07AUG26 |
&SYSDATE9 | Session start date, DATE9. | 07AUG2026 |
&SYSTIME | Session start time | 09:15 |
&SYSDAY | Day of the week | Friday |
&SYSUSERID | Operating-system user ID | rchen |
&SYSLAST | Most recently created data set | WORK.FILTERED |
&SYSERR | Return code of the most recent step | 0 |
footnote1 "Produced by &SYSUSERID on &SYSDAY, &SYSDATE9";
Note that &SYSDATE and &SYSTIME capture the moment the session started, not the moment the statement runs, so a long batch job stamps every page with the same value.
5. Debugging Macro Resolution
Because substitution happens before compilation, a macro bug surfaces as a puzzling DATA step error rather than a macro error. Three tools make the substitution visible.
options symbolgen; /* log every macro variable resolution */
%let region = West;
%put NOTE: region resolves to ®ion; /* writes directly to the log */
%put _USER_; /* lists all user-defined macro variables */
SYMBOLGEN writes a line such as SYMBOLGEN: Macro variable REGION resolves to West for every reference, which immediately exposes the two most common failures: a value carrying unexpected quotation marks, and a reference that never resolved at all.
Exam Tip:
WARNING: Apparent symbolic reference X not resolvedmeans no macro variable namedXexists — usually a typo or a missing name delimiter. The step still runs, substituting the literal text&X, which is why the eventual error message often points somewhere entirely unrelated.
After %let region = West;, which statement displays the title text 'Sales Report for West'?
title 'Sales Report for ®ion';
title "Sales Report for ®ion";
title Sales Report for %region;
title "Sales Report for %region";
Given %let prefix = sales;, which reference generates the data set name sales2026?
&prefix2026
&prefix.2026
&prefix..2026
%prefix.2026
What exactly does %let cost = 180; store in the macro variable COST?
The numeric value 180, usable directly in arithmetic
The four characters '180 ' including a trailing blank
The three characters 180 stored as text, with surrounding blanks stripped
A pointer to a numeric constant in the SAS symbol table
A program logs WARNING: Apparent symbolic reference REGON not resolved and then fails in an apparently unrelated statement. What is the most likely cause and the fastest diagnostic?
The macro variable name is misspelled in the reference; turn on OPTIONS SYMBOLGEN to see every resolution in the log
The macro variable exceeded 32,767 characters; shorten the value
Single quotation marks were used, which always halts the macro processor
The %LET statement must be placed inside a DATA step; move it
Sections you finish are checked off in the contents.