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 &region 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.
Last updated: August 2026

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 %LET statement, 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 %MACRO definitions 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:

  1. Everything is text. %let reportYear = 2026; stores the four characters 2026, 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.
  2. Leading and trailing blanks are stripped. %let region = West ; stores West.
  3. 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.
  4. 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 = "&region";     /* becomes: where Region = "West" */
run;

proc means data=work.filtered mean sum;
   var Sales;
   title "Sales Summary for &region";
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.

CodeResult
title "Report for &region";Report for West — resolved
title 'Report for &region';Report for &region — literal text
where Region = "&region";where Region = "West" — correct
where Region = '&region';Compares Region to the literal string &region, 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, a FOOTNOTE, a WHERE clause, 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 &region/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:

VariableContainsExample
&SYSDATESession start date, DATE7.07AUG26
&SYSDATE9Session start date, DATE9.07AUG2026
&SYSTIMESession start time09:15
&SYSDAYDay of the weekFriday
&SYSUSERIDOperating-system user IDrchen
&SYSLASTMost recently created data setWORK.FILTERED
&SYSERRReturn code of the most recent step0
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 &region;      /* 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 resolved means no macro variable named X exists — 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.

Test Your Knowledge

After %let region = West;, which statement displays the title text 'Sales Report for West'?

A
B
C
D
Test Your Knowledge

Given %let prefix = sales;, which reference generates the data set name sales2026?

A
B
C
D
Test Your Knowledge

What exactly does %let cost = 180; store in the macro variable COST?

A
B
C
D
Test Your Knowledge

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?

A
B
C
D