Week 11, Part 7: Macros for Repetitive Processing¶
This macro’s utility is in automation, dynamic processing, and safety.
- Dynamically loop over rows in a dataset
- Extract variables safely, even if they contain & or %
- Generate reports, filters, or custom SAS code for each row
- Avoid manual, repetitive coding
More specifically, the macro
Takes a dataset (sashelp.class).
Stores all rows in a single macro variable, using a safe delimiter (|) for columns and spaces for rows.
Loops through each row (student) using macro logic.
Extracts variables (name, sex, age) from each row.
Each acts as row (e.g., prints a report for that student).
In [9]:
options nocenter nodate nonumber nosource symbolgen;
ods html close;
proc sql noprint;
select catx('|', name, sex, age)
into :student_list separated by ', '
from sashelp.class;
quit;
%put %superq(student_list); /* safe display */
%put number of values: &sqlobs
The SAS System NOTE: Writing HTML5(SASPY_INTERNAL) Body file: _TOMODS1 NOTE: PROCEDURE SQL used (Total process time): real time 0.00 seconds cpu time 0.00 seconds Alfred|M|14, Alice|F|13, Barbara|F|13, Carol|F|14, Henry|M|14, James|M|12, Jane|F|12, Janet|F|15, Jeffrey|M|13, John|M|12, Joyce|F|11, Judy|F|14, Louise|F|12, Mary|F|15, Philip|M|16, Robert|M|12, Ronald|M|15, Thomas|M|11, William|M|15 SYMBOLGEN: Macro variable SQLOBS resolves to 19 number of values: 19 The SAS System E3969440A681A2408885998500000011
In [11]:
options nocenter nodate nonumber symbolgen;
ods html close;
%macro student_reports;
%local i n obs name sex age;
/* Count number of students */
%let n = %sysfunc(countw(%superq(student_list), %str( )));
%do i = 1 %to &n;
/* Extract one student record */
%let obs = %qscan(%superq(student_list), &i, %str( ));
/* Parse name, sex, age */
%let name = %qscan(&obs,1,|);
%let sex = %qscan(&obs,2,|);
%let age = %qscan(&obs,3,|);
/* Dynamic report for this student */
title "Report for &name (Sex: &sex, Age: &age)";
proc print data=sashelp.class noobs;
where name="&name";
run;
%end;
%mend;
%student_reports
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Alfred | M | 14 | 69 | 112.5 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Alice | F | 13 | 56.5 | 84 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Barbara | F | 13 | 65.3 | 98 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Carol | F | 14 | 62.8 | 102.5 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Henry | M | 14 | 63.5 | 102.5 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| James | M | 12 | 57.3 | 83 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Jane | F | 12 | 59.8 | 84.5 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Janet | F | 15 | 62.5 | 112.5 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Jeffrey | M | 13 | 62.5 | 84 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| John | M | 12 | 59 | 99.5 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Joyce | F | 11 | 51.3 | 50.5 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Judy | F | 14 | 64.3 | 90 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Louise | F | 12 | 56.3 | 77 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Mary | F | 15 | 66.5 | 112 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Philip | M | 16 | 72 | 150 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Robert | M | 12 | 64.8 | 128 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Ronald | M | 15 | 67 | 133 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| Thomas | M | 11 | 57.5 | 85 |
| Name | Sex | Age | Height | Weight |
|---|---|---|---|---|
| William | M | 15 | 66.5 | 112 |
Macro-based automation¶
This approach is often used for:
- Batch reporting (one report per customer/row)
- Dynamic WHERE clauses
- Parameter-driven calculations
You can completely automate tasks without manually changing SAS code each time.