SAS Macros
SAS Macros
Course Notes
SAS® Macro Language Course Notes was developed by Davetta Dunlap and Susan Farmer. Additional
contributions were made by Jim Simon, Warren Repole, Hunter McGhee, Michelle Buchecker,
Michele Ensor, Cynthia Johnson, Johnny Johnson, Linda Jolley, Marjorie Lampton, and Cynthia Zender.
Editing and production support was provided by the Curriculum Development and Support Department.
SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of
SAS Institute Inc. in the USA and other countries. ® indicates USA registration.
Other brand and product names are trademarks of their respective companies.
Table of Contents
Prerequisites ...............................................................................................................................vii
Module 2 Creating and Resolving Macro Variables Prior to Compilation ....... 2-1
Module 5 Creating and Resolving Macro Variables During Execution ............ 5-1
Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
B-1
Course Description
This Live Web course is for experienced SAS programmers who want to build complete macro-based
systems using the SAS macro facility.
This course focuses on the components of the SAS macro facility and how to design, write, and debug
macro systems. Emphasis is placed on understanding how programs with and without macro code are
processed.
To learn more…
For a list of other SAS books that relate to the topics covered in this
Course Notes, USA customers can contact our SAS Publishing Department at
1-800-727-3228 or send e-mail to sasbook@sas.com. Customers outside the
USA, please contact your local SAS office.
Also, see the Publications Catalog on the Web at www.sas.com/pubs for a
complete list of books and a convenient order form.
For Your Information vii
Prerequisites
Before attending this course, students should have completed the SAS® Programming II course or have
equivalent knowledge. Specifically, you should be able to
write and submit SAS programs on your operating system
use LIBNAME, FILENAME, TITLE, and OPTIONS statements
use a DATA step to read from or write to a SAS data set or external data file
use DATA step programming statements such as IF-THEN/ELSE, DO WHILE, DO UNTIL, and
iterative DO
use character functions such as SUBSTR, SCAN, INDEX, and UPCASE
use the LENGTH and RETAIN statements
use SAS data set options such as DROP=, KEEP=, and OBS=
form subsets of data using the WHERE clause
create and use SAS date values, including SAS date constants
execute Base SAS procedures such as SORT, PRINT, CONTENTS, MEANS, FREQ, TABULATE,
and CHART.
Module 1 Introduction to the
SAS Macro Facility
Objectives
State the purpose of the macro facility.
View examples of macro applications.
Identify the tokens in a SAS program.
Describe how a SAS program is tokenized, compiled,
and executed.
Describe the data used in the course examples and
workshops.
9
1.1 Purpose of the Macro Facility 1-3
10
The macro facility is a tool for customizing SAS and for minimizing the amount of program code you
must enter to perform common tasks.
11
1-4 Module 1 Introduction to the SAS Macro Facility
12
Conditional Processing
Example: Generate a detailed report on a daily basis.
Generate an additional report every Friday,
summarizing data on a weekly basis.
Repetitive Processing
Example: Generate a similar report each year from
2003 to 2005.
15
Data-Driven Applications
Example: Create a separate subset of a data set for each
unique value of a selected variable.
data Boston Dallas Seattle;
set perm.schedule;
select(location);
when("Boston") output Boston;
when("Dallas") output Dallas;
when("Seattle") output Seattle;
otherwise;
end;
run;
16
1-6 Module 1 Introduction to the SAS Macro Facility
Step 1:
write and debug the desired SAS program without any
macro coding
make sure the SAS program runs with hardcoded
programming constants on a fixed set of data.
17
Beginning the development process in this manner enables rapid development and debugging because
syntax and logic at the SAS code level is isolated from syntax and logic at the macro level.
maintenance time.
18
1.1 Purpose of the Macro Facility 1-7
Student Activity
Substitute &sysdate9 for 25AUG2004 and submit the
following program:
sa-sysdate
19
1-8 Module 1 Introduction to the SAS Macro Facility
Program Flow
A SAS program can be any combination of
DATA steps and PROC steps
global statements
22
Program Flow
Input
InputStack
Stack
Batch or
SUBMIT Stored Noninteractive
Command Process Submission
data
data new;
new; %STPBEGIN;
%STPBEGIN; //SYSIN
//SYSIN DD
DD **
set
set perm.mast;
perm.mast; proc
proc print
print data=new;
data=new; options
options nodate;
nodate;
bonus=wage*0.1;
bonus=wage*0.1; run;
run; proc
proc sql;
sql;
run;
run; proc means data=new;
proc means data=new; select
select **
proc
proc print;
print; run;
run; from
from perm.mast;
perm.mast;
run;
run; %STPEND;
%STPEND; quit;
quit;
23
1.2 Program Flow 1-9
Program Flow
After SAS code is in the input stack, a component of SAS
called the word scanner
reads the text in the input stack, character by
character, left-to-right, top-to-bottom
breaks the text into fundamental units called tokens.
data
data
Word new
new
Scanner ;;
set
set perm.mast;
perm.mast;
bonus=wage*0.1;
bonus=wage*0.1;
Input run;
run;
proc
proc print;
print;
Stack run;
run;
24
Program Flow
The word scanner passes the tokens, one at a time, to
the appropriate compiler, as the compiler demands.
Compiler data
data new;
new;
set
set
Word Scanner perm
perm
..
mast
mast
;;
25
Program Flow
The compiler
requests tokens until it receives a semicolon
performs a syntax check on the statement
repeats this process for each statement.
SAS
suspends the compiler when a step boundary is
encountered
executes the compiled code if there are no
compilation errors
repeats this process for each step.
26
1-10 Module 1 Introduction to the SAS Macro Facility
Tokenization
The word scanner recognizes four classes of tokens:
literal tokens
number tokens
name tokens
special tokens.
27
Literal Tokens
A literal token is a string of characters enclosed in single
or double quotes.
28
Number Tokens
Number tokens can be
integer numbers, including SAS date constants
floating point numbers, containing a decimal point
and/or exponent.
Examples: 3
3.
3.5
-3.5
’01jan2002’d
5E8
7.2E-4
29
1.2 Program Flow 1-11
Name Tokens
Name tokens contain one or more characters beginning
with a letter or underscore and continuing with
underscores, letters, or numerals.
Examples: infile
_n_
item3
univariate
dollar10.2
Special Tokens
Special tokens can be any character, or combination of
characters, other than a letter, numeral, or underscore.
Examples: * / + - ** ; $ ( ) . & % @ # = ||
31
Tokenization
A token ends when the word scanner detects
the beginning of another token
Blanks
are not tokens
delimit tokens.
33
1-12 Module 1 Introduction to the SAS Macro Facility
Example
Tokens 1. var
2. x1
3. -
4. x10
5. z
6. ;
34
Example
Tokens 1. title
2. 'Report for May'
3. ;
35
Question
How many tokens are present in each of these
statements?
bonus=3.2*(wage-2000);
plot date*revenue='$'/vref='30jun2001'd;
36
1.2 Program Flow 1-13
Processing Tokens
flow1.sas
By executing the program below, one token at a time in the Program Editor, you can observe in the SAS
log which tokens trigger SAS to compile and execute code.
proc
options
;
proc
print
;
run
;
1. Which token triggers execution of the PROC OPTIONS step, displaying the current settings of
system options in the SAS log?
2. Which token triggers an error message in the log window indicating that no data set is available to be
printed?
3. Which token triggers a note indicating that SAS stopped processing the step?
1-14 Module 1 Introduction to the SAS Macro Facility
Macro Triggers
During word scanning, two token sequences are
recognized as macro triggers:
%name-token a macro statement, function, or call
&name-token a macro variable reference.
42
Macro Statements
Macro statements
begin with a percent sign (%) followed by a name token
43
%PUT
%PUT text;
text;
44
1.2 Program Flow 1-15
45
Program Flow
The %PUT statement is submitted.
Compiler
Macro Processor
Word
Scanner
Input %put
%put Hi
Hi Mom!;
Mom!;
Stack
46
Program Flow
The statement is tokenized.
Compiler
Macro Processor
Word %%
Scanner put
put
Hi
Hi
Mom
Mom
!!
;;
Input
Stack
47
1-16 Module 1 Introduction to the SAS Macro Facility
Program Flow
When a macro trigger is encountered, it is passed to the
macro processor for evaluation.
Compiler
Macro Processor
Word %put
%put
Scanner
Hi
Hi
Mom
Mom
!!
;;
Input
Stack
48
Program Flow
The macro processor requests tokens until a semicolon
is encountered, and then it executes the macro statement.
Compiler
Macro Processor
Word %put
%put Hi
Hi Mom!;
Mom!;
Scanner
Input
Stack
49
Quick Quiz
What will be printed in the log if you add quotes around the
text in the %PUT statement?
Compiler
Macro Processor
Word
Scanner
50
1.2 Program Flow 1-17
51
1-18 Module 1 Introduction to the SAS Macro Facility
These data sets are stored in a SAS data library with a libref of perm.
1.3 Course Data 1-19
Listing of PERM.COURSES
Course_
Obs Code Course_Title Days Fee
The program used to create the perm.all data set is shown below.
proc sql;
create table perm.all as
select students.student_name,
schedule.course_number,
paid, courses.course_code,
location, begin_date,
teacher, course_title, days, fee,
student_company, city_state
from perm.schedule, perm.students,
perm.register, perm.courses
where schedule.course_code =
courses.course_code and
schedule.course_number =
register.course_number and
students.student_name =
register.student_name
order by students.student_name,
courses.course_code;
quit;
1-24 Module 1 Introduction to the SAS Macro Facility
Sort Information
Course_ Course_
Obs Student_Name Number Paid Code Location
Begin_
Obs Date Teacher Course_Title
Student Activity
Examine the contents of the perm library.
Submit the program:
sa-contents
60
1-26 Module 1 Introduction to the SAS Macro Facility
Module 1 Summary
State the purpose of the macro facility.
View examples of macro applications.
Identify the tokens in a SAS program.
Describe how a SAS program is tokenized, compiled,
and executed.
Describe the data used in the course examples and
workshops.
61
Module 2 Creating and Resolving
Macro Variables Prior to Compilation
Objectives
Understand macro variables.
Describe where macro variables are stored.
Identify the two types of macro variables.
Identify selected automatic macro variables.
Display automatic macro variables in the SAS log.
Understand how macro variable references are
handled by the word scanner and macro processor.
Create user-defined macro variables.
Display values of user-defined macro variables in the
SAS log.
Place a macro variable reference adjacent to text or
another macro variable reference.
Macro Variables
Macro variables store text, including
complete or partial SAS steps
4
2.1 Introduction to Macro Variables 2-3
Macro Variables
Macro variables in the global symbol table
are global in scope (available any time)
7
2-4 Module 2 Creating and Resolving Macro Variables Prior to Compilation
10
2.2 Automatic Macro Variables 2-5
Name Description
SYSLAST name of most recently created SAS data set in
the form libref.name. If no data set has been
created, the value is _NULL_.
11
%put _automatic_;
12
13
2-6 Module 2 Creating and Resolving Macro Variables Prior to Compilation
Student Activity
Display in the SAS log the name of every automatic
macro variable.
Find the value of SYSSCP.
%put _automatic_;
14
2.3 Macro Variable References 2-7
18
2-8 Module 2 Creating and Resolving Macro Variables Prior to Compilation
Compiler
Macro Processor
Word
Scanner
Symbol Table
%put
%put Today
Today is
is &sysday;
Input &sysday;
Stack SYSDAY Tuesday
SYSLAST _NULL_
19
Compiler
Macro Processor
Word %put
%put
Scanner
Symbol Table
Today
Today is
is &sysday;
Input &sysday;
Stack SYSDAY Tuesday
SYSLAST _NULL_
20
Compiler
Macro Processor
Word %put
%put Today
Today is
is &sysday;
&sysday;
Scanner
Symbol Table
Input
Stack SYSDAY Tuesday
SYSLAST _NULL_
21
2.3 Macro Variable References 2-9
Compiler
Macro Processor
Word %put
%put Today
Today is
is &sysday;
&sysday;
Scanner
Symbol Table
Input
Stack SYSDAY Tuesday
SYSLAST _NULL_
22
Compiler
Macro Processor
Word %put
%put Today
Today is
is Tuesday;
Tuesday;
Scanner
Symbol Table
Input
Stack SYSDAY Tuesday
SYSLAST _NULL_
23
Compiler
Macro Processor
Word %put
%put Today
Today is
is Tuesday;
Tuesday;
Scanner
Symbol Table
Input
Stack SYSDAY Tuesday
SYSLAST _NULL_
24
2-10 Module 2 Creating and Resolving Macro Variables Prior to Compilation
Compiler
Macro Processor
Word
Scanner
Symbol Table
Input proc
proc print
print data=perm.all;
data=perm.all;
title
title "Today
"Today is
is &sysday";
&sysday";
Stack run;
SYSDAY Tuesday
run; SYSLAST _NULL_
27
proc
proc print
print data=perm.all;
data=perm.all;
Compiler title
title
Macro Processor
Word ""
Today
Today
Scanner is
is
Symbol Table
Input
&sysday";
&sysday";
Stack run;
SYSDAY Tuesday
run; SYSLAST _NULL_
28
2.3 Macro Variable References 2-11
proc
proc print
print data=perm.all;
data=perm.all;
Compiler title
title
Macro Processor
Word "" &sysday
&sysday
Today
Today
Scanner is
is
Symbol Table
Input ";
";
Stack run;
run;
SYSDAY Tuesday
SYSLAST _NULL_
29
proc
proc print
print data=perm.all;
data=perm.all;
Compiler title
title
Macro Processor
Word "" &sysday
&sysday
Today
Today
Scanner is
is
Symbol Table
Input
Stack ";
"; SYSDAY Tuesday
run;
run; SYSLAST _NULL_
30
proc
proc print
print data=perm.all;
data=perm.all;
Compiler title
title
Macro Processor
Word ""
Today
Scanner Today
is
is
Symbol Table
Input
Stack Tuesday";
Tuesday"; SYSDAY Tuesday
run;
run; SYSLAST _NULL_
31
2-12 Module 2 Creating and Resolving Macro Variables Prior to Compilation
proc
proc print
print data=perm.all;
data=perm.all;
Compiler title
title
Macro Processor
Word ""
Today
Today
Scanner is
is
Tuesday
Tuesday
""
Symbol Table
Input
Stack ;; SYSDAY Tuesday
run;
run; SYSLAST _NULL_
32
proc
proc print
print data=perm.all;
data=perm.all;
Compiler title
title "Today
"Today is
is Tuesday"
Tuesday"
Macro Processor
Word
Scanner
Symbol Table
Input
Stack ;; SYSDAY Tuesday
run;
run; SYSLAST _NULL_
33
proc
proc print
print data=perm.all;
data=perm.all;
Compiler title
title "Today
"Today is
is Tuesday";
Tuesday";
Macro Processor
Word
Scanner
run;
run;
Symbol Table
Input
Stack SYSDAY Tuesday
SYSLAST _NULL_
34
2.3 Macro Variable References 2-13
Quick Quiz
What is the title if you submit the following program?
Compiler
Macro Processor
Word
Scanner
Symbol Table
Input proc
proc print
print data=perm.all;
data=perm.all;
title
title 'Today
'Today is
is &sysday';
Stack run;
&sysday'; SYSDAY Tuesday
run;
SYSLAST _NULL_
35
40
„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ…ƒƒƒ…ƒƒƒƒƒƒƒƒƒƒ†
‚COURSE ‚ N ‚ Sum ‚
‡ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒˆƒƒƒˆƒƒƒƒƒƒƒƒƒƒ‰
‚Artificial Intelligence ‚ 25‚ $10,000‚
‡ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒˆƒƒƒˆƒƒƒƒƒƒƒƒƒƒ‰
‚Basic Telecommunications ‚ 18‚ $14,310‚
‡ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒˆƒƒƒˆƒƒƒƒƒƒƒƒƒƒ‰
‚Computer Aided Design ‚ 19‚ $30,400‚
‡ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒˆƒƒƒˆƒƒƒƒƒƒƒƒƒƒ‰
‚Database Design ‚ 23‚ $8,625‚
‡ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒˆƒƒƒˆƒƒƒƒƒƒƒƒƒƒ‰
‚Local Area Networks ‚ 24‚ $15,600‚
‡ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒˆƒƒƒˆƒƒƒƒƒƒƒƒƒƒ‰
‚Structured Query Language ‚ 24‚ $27,600‚
‡ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒˆƒƒƒˆƒƒƒƒƒƒƒƒƒƒ‰
‚TOTALS ‚133‚ $106,535‚
Šƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‹ƒƒƒ‹ƒƒƒƒƒƒƒƒƒƒŒ
Unresolved Reference
Example: Reference a non-existent macro variable.
Compiler
Macro Processor
Word
Scanner
Symbol Table
proc
proc print
print data=perm.exp;
Input title
data=perm.exp;
title "Expenses
"Expenses for
for R&D";
R&D";
Stack run;
run;
SYSDAY Tuesday
SYSLAST _NULL_
42
Unresolved Reference
The macro trigger is passed to the macro processor for
evaluation.
proc
proc print
print data=perm.exp;
Compiler data=perm.exp;
title
title
Macro Processor
Word ""
Scanner
Expenses
Expenses &D
&D
for
for
RR
Symbol Table
";
Input run;
";
run;
Stack SYSDAY Tuesday
SYSLAST _NULL_
43
Unresolved Reference
The macro processor writes a warning to the SAS log
when it cannot resolve a reference.
Macro Processor
Word ""
Scanner
Expenses
Expenses &D
&D
for
for
RR
Symbol Table
";
Input run;
";
run;
Stack SYSDAY Tuesday
SYSLAST _NULL_
44
2.3 Macro Variable References 2-15
Unresolved Reference
If the macro processor cannot resolve a reference, it
passes the tokens back to the word scanner and the word
scanner passes them to the compiler.
proc
proc print
print data=perm.exp;
data=perm.exp;
Compiler title
title "Expenses
"Expenses for
for R&D"
R&D"
Macro Processor
Word ;;
run;
run;
Scanner
Symbol Table
Input
Stack SYSDAY Tuesday
SYSLAST _NULL_
45
Compiler
Macro Processor
Word
Scanner
Symbol Table
proc
proc print
print data=&syslast;
Input title
data=&syslast;
title "Listing
"Listing of
of &syslast";
&syslast";
Stack run;
run;
SYSDAY Tuesday
SYSLAST PERM.ALL
46
Macro Processor
Word
Scanner &syslast
&syslast
Symbol Table
Input ;;
title
title "Listing
"Listing of
of &syslast";
&syslast";
Stack run;
run;
SYSDAY Tuesday
SYSLAST PERM.ALL
47
2-16 Module 2 Creating and Resolving Macro Variables Prior to Compilation
proc
proc print
print data=
Compiler data=
Macro Processor
Word
&syslast
Scanner
Symbol Table
;;
Input title
title "Listing
"Listing of
of &syslast";
&syslast";
Stack run;
run;
SYSDAY Tuesday
SYSLAST PERM.ALL
48
proc
proc print
print data=
Compiler data=
Macro Processor
Word
Scanner
Symbol Table
PERM.ALL;
Input title
PERM.ALL;
title "Listing
"Listing of
of &syslast";
&syslast";
Stack run;
run;
SYSDAY Tuesday
SYSLAST PERM.ALL
49
Compiler proc
proc print
print data=PERM.ALL;
data=PERM.ALL;
Macro Processor
Word
Scanner
Symbol Table
Input title
title "Listing
"Listing of
of &syslast";
&syslast";
Stack run;
run;
SYSDAY Tuesday
SYSLAST PERM.ALL
50
2.3 Macro Variable References 2-17
proc
proc print
print data=PERM.ALL;
data=PERM.ALL;
Compiler title
title "Listing
"Listing of
of PERM.ALL";
PERM.ALL";
Macro Processor
Word run;
run;
Scanner
Symbol Table
Input
Stack SYSDAY Tuesday
SYSLAST PERM.ALL
51
%LET
%LET variable=value;
variable=value;
55
56
2.4 User-Defined Macro Variables 2-19
56
Value
%let name= Ed Norton ;
%let name2=' Ed Norton ';
%let title="Joan's Report";
%let start=;
%let sum=3+4;
%let total=0;
%let total=&total+∑
%let x=varlist;
%let &x=name age height;
57
Value
%let name= Ed Norton ; Ed Norton
%let name2=' Ed Norton '; ' Ed Norton '
%let title="Joan's Report"; "Joan's Report"
%let start=;
%let sum=3+4; 3+4
%let total=0; 0
%let total=&total+∑
%let x=varlist;
%let &x=name age height;
59
Value
%let name= Ed Norton ; Ed Norton
%let name2=' Ed Norton '; ' Ed Norton '
%let title="Joan's Report"; "Joan's Report"
%let start=;
%let sum=3+4; 3+4
%let total=0;
%let total=&total+∑ 0+3+4
%let x=varlist; varlist
%let &x=name age height;
61
Quick Quiz
What is the name of the macro variable created with this
%LET statement?
Value
%let name= Ed Norton ; Ed Norton
%let name2=’ Ed Norton ’; ' Ed Norton '
%let title="Joan’s Report"; "Joan's Report"
%let start=;
%let sum=3+4; 3+4
%let total=0;
%let total=&total+∑ 0+3+4
%let x=varlist; varlist
%let &x=name age height;
Value
%let name= Ed Norton ; Ed Norton
%let name2=' Ed Norton '; ' Ed Norton '
%let title="Joan's Report"; "Joan's Report"
%let start=;
%let sum=3+4; 3+4
%let total=0;
%let total=&total+∑ 0+3+4
%let x=varlist; varlist
%let &x=name age height; name age height
macvarname=varlist
63
%let site=DALLAS;
title "REVENUES FOR &site TRAINING CENTER";
proc tabulate data=perm.all(keep=location
course_title fee);
where upcase(location)="&site";
class course_title;
var fee;
table course_title=’ ’ all=’TOTALS’,
fee=’ ’*(n*f=3. sum*f=dollar10.)
/ rts=30 box=’COURSE’;
run;
let1
64
65
2-22 Module 2 Creating and Resolving Macro Variables Prior to Compilation
66
%put _user_;
Partial SAS Log
4 %put _user_;
GLOBAL DATE 05JAN2004
GLOBAL AMOUNT 975
GLOBAL CITY Dallas
67
OPTIONS
OPTIONSSYMBOLGEN;
SYMBOLGEN;
68
2.4 User-Defined Macro Variables 2-23
69
Quick Quiz
Global Symbol Table
CITY Dallas
DATE 05JAN2004
AMOUNT 975
%SYMDEL
%SYMDEL macro-variables;
macro-variables;
72
2-24 Module 2 Creating and Resolving Macro Variables Prior to Compilation
73
77
78
2-26 Module 2 Creating and Resolving Macro Variables Prior to Compilation
79
%let year=2000;
%let month=jan;
proc chart data=perm.y&year&month;
hbar week / sumvar=sale;
run;
proc plot data=perm.y&year&month;
plot sale*day;
run;
80
81
2.5 Delimiting Macro Variable Names 2-27
82
83
84
2-28 Module 2 Creating and Resolving Macro Variables Prior to Compilation
Quick Quiz
Given the following code, which macro variable reference
gets passed to the macro processor?
&graphics
&graphicschart
/* GRAPHICS should be null or G */
%let graphics=g;
%let year=2000;
%let month=jan;
%let var=sale;
proc &graphicschart data=perm.y&year&month;
hbar week / sumvar=&var;
run;
proc &graphicsplot data=perm.y&year&month;
plot &var*day;
run;
85
Submit your answer as a text question.
87
88
2.5 Delimiting Macro Variable Names 2-29
%let graphics=g;
%let year=2000;
%let month=jan;
%let var=sale;
proc &graphics.chart data=perm.y&year&month;
hbar week / sumvar=&var;
run;
proc &graphics.plot data=perm.y&year&month;
plot &var*day;
run;
89
Quick Quiz
What is the token that gets created when &graphics.chart
gets resolved?
%let graphics=g;
%let year=90;
%let month=jan;
%let var=sale;
proc &graphics.chart data=perm.y&year&month;
hbar week / sumvar=&var;
run;
proc &graphics.plot data=perm.y&year&month;
plot &var*day;
run;
92
2-30 Module 2 Creating and Resolving Macro Variables Prior to Compilation
93
%let lib=perm;
...
libname &lib 'SAS-data-library';
proc &graphics.chart data=&lib..y&year&month;
...
proc &graphics.plot data=&lib..y&year&month;
96
2.5 Delimiting Macro Variable Names 2-31
97
Module 2 Summary
Understand macro variables.
Describe where macro variables are stored.
Identify the two types of macro variables.
Identify selected automatic macro variables.
Display automatic macro variables in the SAS log.
Understand how macro variable references are
handled by the word scanner and macro processor.
Create user-defined macro variables.
Display values of user-defined macro variables in the
SAS log.
Place a macro variable reference adjacent to text or
another macro variable reference.
100
2-32 Module 2 Creating and Resolving Macro Variables Prior to Compilation
Session 1 Summary
Discussed the purpose and application of the macro
facility.
Described how a SAS program is tokenized, compiled,
and executed.
Used system and user-defined macro variables.
Displayed user-defined macro variables in the SAS
log.
Placed a macro variable reference adjacent to text or
another macro variable reference.
101
Module 3 Using Macro Functions
Objectives
Use macro functions to
manipulate character strings
perform arithmetic
Macro Functions
Macro functions
have similar syntax as corresponding DATA step
character functions
yield similar results
8
3.1 Basic Macro Functions 3-3
Macro Functions
Selected character string manipulation functions:
%UPCASE translates letters from lowercase to uppercase.
%SUBSTR extracts a substring from a character string.
%SCAN extracts a word from a character string.
%INDEX searches a character string for specified text.
%LENGTH returns the length of a character string or text
expression.
Other functions:
%SYSFUNC executes SAS functions.
%EVAL performs arithmetic and logical operations.
%BQUOTE protects blanks and other special characters.
9
Case Sensitivity
Character comparisons are case-sensitive.
Example: Create a summary of total fees outstanding for
each course.
%let paidval=n;
proc means data=perm.all sum maxdec=0;
where paid="&paidval";
var fee;
class course_title;
title "Courses with fee status=&paidval";
run;
upcase1
10
Quick Quiz
Partial Log
539 %let paidval=n;
540 proc means data=perm.all sum maxdec=0;
541 where paid="&paidval";
542 var fee;
543 class course_title;
544 title "Courses with fee status=&paidval";
545 run;
11
3-4 Module 3 Using Macro Functions
Case Sensitivity
Partial Log
539 %let paidval=n;
540 proc means data=perm.all sum maxdec=0;
541 where paid="&paidval";
542 var fee;
543 class course_title;
544 title "Courses with fee status=&paidval";
545 run;
13
%UPCASE(argument)
%UPCASE(argument)
14
%let paidval=n;
proc means data=perm.all sum maxdec=0;
where paid="%upcase(&paidval)";
var fee;
class course_title;
title "Courses with fee status=&paidval";
run;
upcase2
15
3.1 Basic Macro Functions 3-5
16
%SUBSTR(argument,
%SUBSTR(argument,position
position<,n>)
<,n>)
continued...
17
3-6 Module 3 Using Macro Functions
%SUBSTR(argument,
%SUBSTR(argument,position
position<,n>)
<,n>)
18
The values of position and n can also be the result of an arithmetic expression that yields an
integer. For example,
%substr(&var,%length(&var)-1)
returns the last two characters of the value of the macro variable VAR.
19
3.1 Basic Macro Functions 3-7
Quick Quiz
Question: Use today’s date. What is the first SAS date
constant in the WHERE statement?
proc print data=perm.schedule;
where begin_date between
"01%substr(&sysdate9,3)"d and
"&sysdate9"d;
title "All Courses Held So Far This Month";
title2 "(as of &sysdate9)";
run;
20
"01%substr(&sysdate9,3)"d
21
22
3-8 Module 3 Using Macro Functions
%SCAN(argument,
%SCAN(argument,nn <<,,delimiters>)
delimiters>)
23
%SCAN(argument,
%SCAN(argument,nn <<,,delimiters>)
delimiters>)
macro functions
macro calls.
24
3.1 Basic Macro Functions 3-9
data work.current;
set perm.schedule;
where year(begin_date) =
year("&sysdate9"d);
run;
%let libref=%scan(&syslast,1);
%let dsname=%scan(&syslast,2,.);
proc datasets lib=&libref nolist;
title "Contents of Data Set &syslast";
contents data=&dsname;
run;
quit;
scan1
25
&syslast
resolves: %let libref=%scan(work.current,1);
%scan
executes: %let libref=work;
26
3-10 Module 3 Using Macro Functions
31
options symbolgen; 1 2 3
%let datastep=data test; x=1; run;
%put &datastep;
Mask
You can use macro quoting functions to remove the normal
syntactic meaning of tokens.
33
%BQUOTE(argument)
%BQUOTE(argument)
34
The %BQUOTE function is one of several macro quoting functions designed for specialized purposes.
35
3.2 Special Macro Functions 3-13
36
bquote1
Quick Quiz
Given the following code:
%let name=Valdez,Sanita;
%let lname=%scan(&name,1);
37
%let name=Valdez,Sanita;
%let lname=%scan(&name,1);
38
3-14 Module 3 Using Macro Functions
%let lname=%scan(Valdez,Sanita,1);
%let name=Valdez,Sanita;
%let lname=%scan(%bquote(&name),1);
%put &lname;
1 2
40
53 %let name=Valdez,Sanita;
54 %let lname=%scan(%bquote(&name),1);
55 %put &lname;
Valdez
41
3.2 Special Macro Functions 3-15
%EVAL(expression)
%EVAL(expression)
42
%let firstyr=2004;
%let numyears=2;
%let finalyr=%eval(&firstyr+&numyears-1);
proc print data=perm.schedule;
where year(begin_date) between
&firstyr and &finalyr;
title "All Courses Scheduled";
title2 "&firstyr through &finalyr";
run;
eval1
44
%SYSFUNC(SAS
%SYSFUNC(SASfunction(argument(s))
function(argument(s))<,format>)
<,format>)
46
generates
Report Produced on 11JUN2004
at 09:21
47
title "%sysfunc(today(),weekdate.)";
title2 "%sysfunc(time(),time8.)";
generates
48
3.2 Special Macro Functions 3-17
%let thisyr=%sysfunc(today(),year4.);
%let lastyr=%eval(&thisyr-1);
proc print data=perm.schedule;
where year(begin_date) between &lastyr and &thisyr;
title1 "Courses Scheduled &lastyr and &thisyr";
title2 "(as of &sysdate9)";
run;
sysfunc1
49
50
3-18 Module 3 Using Macro Functions
51
Variable Information functions include functions such as VNAME and VLABEL. For a complete
list, see “Functions and CALL Routines” in the SAS® Language Reference: Dictionary.
Because %SYSFUNC is a macro function, you do not need to enclose character values in
quotation marks as you do in DATA step functions. Use commas to separate all arguments in
DATA step functions within %SYSFUNC. You cannot use argument lists preceded by the word
OF.
Module 3 Summary
Use macro functions to manipulate character strings.
Use macro functions to perform arithmetic.
Use macro functions to execute SAS functions.
54
Module 4 Defining and Executing
Macro Programs
Objectives
Define and call a simple macro.
Control macro storage.
Define and call macros with parameters.
Describe the difference between positional and
keyword parameters.
Defining a Macro
A macro or macro definition enables you to write macro
programs.
General form of a macro definition:
%MACRO
%MACRO macro-name;
macro-name;
macro-text
macro-text
%MEND
%MEND<macro-name>;
<macro-name>;
Macro Compilation
When a macro definition is submitted,
macro language statements are
Do not name a macro with the name of a macro statement or function (LET or SCAN, for
example). Refer to the documentation for a complete list of reserved names.
Macro Compilation
The MCOMPILENOTE=ALL option issues a note to the
SAS log after a macro definition has compiled.
OPTIONS
OPTIONSMCOMPILENOTE=ALL
MCOMPILENOTE=ALL||NONE;
NONE;
6
4-4 Module 4 Defining and Executing Macro Programs
Macro Compilation
Example: Submit a macro definition.
options mcompilenote=all;
%macro time;
%put The current time is %sysfunc
(time(),time11.2).;
%mend time;
macro1
Macro Storage
Example: Produce a list of compiled macros stored in the
default temporary catalog work.sasmacr.
8
4.1 Defining and Calling a Macro 4-5
Calling a Macro
A macro call
causes the macro to execute
%macro-name
%macro-name
Placing a semicolon after a macro call may insert an inappropriate semicolon into the resulting
program, leading to errors during compilation or execution.
Calling a Macro
Example: Call the TIME macro.
%time
10
4-6 Module 4 Defining and Executing Macro Programs
Student Activity
Example: Submit and call the TIME macro.
%time
sa-macro1
11
Program Flow
When the macro processor receives %macro-name, it
1. searches the designated SAS catalog
(WORK.SASMACR by default) for an entry named
macro-name.MACRO
2. executes compiled macro language statements
3. sends any remaining text to the input stack for word
scanning
4. pauses while the word scanner tokenizes the
inserted text and SAS code executes
5. resumes execution of macro language statements
after the SAS code executes.
13
Example
A macro can generate SAS code.
%macro printdsn;
proc print data=&dsn;
var &vars;
run;
%mend;
macro2
14
4.1 Defining and Calling a Macro 4-7
Example
Example: Call the PRINTDSN macro. Precede the call
with %LET statements that populate macro
variables referenced within the macro.
%let dsn=perm.courses;
%let vars=days fee;
%printdsn
15
Program Flow
Example: Submit the %LET statements and call the
PRINTDSN macro.
17
Program Flow
The macro processor executes the %LET statements and
populates the symbol table.
18
4-8 Module 4 Defining and Executing Macro Programs
Program Flow
When the macro processor receives %PRINTDSN, it locates
PRINTDSN.MACRO within the work.sasmacr catalog.
19
Program Flow
The macro processor opens PRINTDSN.MACRO. There
are no macro language statements to execute.
Program Flow
The macro processor places the macro text on the input
stack.
Program Flow
Macro activity pauses while the word scanner tokenizes
text placed on the input stack by the macro processor.
Program Flow
Macro variable references are passed to the macro
processor.
Program Flow
Symbolic substitution is performed. Word scanning
continues.
Program Flow
When a step boundary is encountered, SAS executes the
compiled step as macro activity remains paused. Macro
activity stops when the %MEND statement is encountered.
Macro Execution
The SAS log reflects that a PROC PRINT step executed.
NOTE: There were 6 observations read from the data set PERM.COURSES.
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
26
Macro Execution
The MPRINT option writes to the SAS log the text sent to
the SAS compiler as a result of macro execution.
General form of the MPRINT|NOMPRINT option:
OPTIONS
OPTIONSMPRINT;
MPRINT;
OPTIONS
OPTIONSNOMPRINT;
NOMPRINT;
27
4.1 Defining and Calling a Macro 4-11
Macro Execution
Example: Set the MPRINT option before calling the
macro.
NOTE: There were 6 observations read from the data set PERM.COURSES.
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds
28
Macro-generated code is treated as a series of tokens. The MPRINT option shows each statement
on a new line without indentation.
Macro Storage
Example: Produce a list of compiled macros stored in the
default temporary catalog work.sasmacr.
29
4-12 Module 4 Defining and Executing Macro Programs
Macro Storage
Macros are stored in the work library, by default.
OPTIONS
OPTIONSMSTORED
MSTOREDSASMSTORE=libref
SASMSTORE=libref;;
30
Macro Storage
General form of a macro definition for permanent macro
storage:
%MACRO
%MACRO macro-name
macro-name //STORE;
STORE;
macro-text
macro-text
%MEND
%MEND macro-name;
macro-name;
31
Macro Storage
Example: Store the PRINTDSN macro in a permanent
library.
libname perm '.';
options mstored sasmstore=perm;
%macro printdsn / store;
proc print data=&dsn;
var &vars;
run;
%mend printdsn;
Macro Storage
General form of a macro definition for permanent macro
storage and storage of the macro source code:
%MACRO
%MACRO macro-name
macro-name //STORE
STORE <SOURCE>;
<SOURCE>;
macro-text
macro-text
%MEND
%MEND macro-name;
macro-name;
34
Macro Storage
Example: Store the PRINTDSN macro and the macro
source code in a permanent library.
libname perm '.';
options mstored sasmstore=perm;
%macro printdsn / store source;
proc print data=&dsn;
var &vars;
run;
%mend printdsn;
Macro Storage
Use %COPY statement to store macro source code.
%COPY
%COPY macro-name
macro-name //SOURCE
SOURCE
<OUT='external
<OUT='externalfile'
file'>;
>;
36
4-14 Module 4 Defining and Executing Macro Programs
Macro Storage
Example: Copy the source code from the stored
PRINTDSN macro to the SAS log.
37
Introduction
Example: Note macro variable references within the
PRINTDSN macro.
%macro printdsn;
proc print data=&dsn;
var &vars;
run;
%mend;
41
Introduction
Example: Call the macro twice, each time substituting
different values of the macro variables DSN
and VARS.
%let dsn=perm.courses;
%let vars=days fee;
%printdsn
%let dsn=perm.schedule;
%let vars=location teacher;
%printdsn
The user must submit three lines per macro call. How
can this be simplified?
42
4-16 Module 4 Defining and Executing Macro Programs
Macro Parameters
Macros can be defined with a parameter list of macro
variables referenced within the macro.
%macro printdsn(dsn,vars);
proc print data=&dsn;
var &vars;
run;
%mend;
43
Macro Parameters
Example: Call the PRINTDSN macro and provide
parameter values.
%macro printdsn(dsn,vars);
proc print data=&dsn;
var &vars;
run;
%mend;
%printdsn(perm.courses,days fee)
44
Macro Parameters
General form of a macro definition with a parameter list:
%MACRO
%MACRO macro-name(parameter-1,
macro-name(parameter-1, …
… parameter-n);
parameter-n);
macro
macro text
text
%MEND;
%MEND;
comma-delimited.
45
4.2 Macro Parameters 4-17
Macro Parameters
General form of a macro call with parameters:
%macro-name(value-1,
%macro-name(value-1, …
…value-n)
value-n)
comma-delimited.
46
To assign a null value to one or more positional parameters, use commas as placeholders for the
omitted values.
48
Quick Quiz
Does a %LET statement outside of a macro program
create a macro variable in the global or local symbol
table?
49
Positional Parameters
Positional parameters use a one-to-one correspondence
between
parameter names supplied on the macro definition
%macro printdsn(dsn,vars);
proc print data=&dsn;
var &vars;
run;
%mend;
%printdsn(perm.courses,days fee)
51
4.2 Macro Parameters 4-19
Positional Parameters
%macro attend(opts, start, stop);
%let start=%upcase(&start);
%let stop=%upcase(&stop);
proc freq data=perm.all;
where begin_date between "&start"d and "&stop"d;
table location / &opts;
title1 "Enrollment from &start to &stop";
run;
%mend;
options mprint;
%attend(nocum,01jan2005,31dec2005)
%attend(,01oct2005,31dec2005)
param1
52
4-20 Module 4 Defining and Executing Macro Programs
options mprint;
%attend(nocum,01jan2005,31dec2005)
%attend(,01oct2005,31dec2005)
Keyword Parameters
General form of a macro call with keyword parameters:
%macro-name(keyword=value,
%macro-name(keyword=value,…,
…,keyword=value)
keyword=value)
Keyword Parameters
Example: Assign default parameter values by defining the
macro with keyword parameters.
%macro attend(opts=,start=01jan05,stop=31dec05);
%let start=%upcase(&start);
%let stop=%upcase(&stop);
proc freq data=perm.all;
where begin_date between
"&start"d and "&stop"d;
table location / &opts;
title1 "Enrollment from &start to &stop";
run;
%mend;
options mprint;
%attend(opts=nocum)
%attend(stop=30jun05,opts=nocum nopercent)
%attend()
param2
56
4-22 Module 4 Defining and Executing Macro Programs
options mprint;
%attend(opts=nocum)
%attend(stop=30jun2005,opts=nocum nopercent)
%attend()
What are the values of the omitted parameters in each call?
Partial SAS Log for %attend(opts=nocum)
MPRINT(ATTEND): proc freq data=perm.all;
MPRINT(ATTEND): where begin_date between "01JAN2005"d and "31DEC2005"d;
MPRINT(ATTEND): table location / nocum;
MPRINT(ATTEND): title1 "Enrollment from 01JAN2005 to 31DEC2005";
NOTE: There were 299 observations read from the dataset PERM.ALL.
WHERE ((begin_date>='01JAN2005'D and begin_date<='31DEC2005'D));
NOTE: PROCEDURE FREQ used:
real time 0.12 seconds
cpu time 0.10 seconds
62
NOTE: There were 299 observations read from the data set PERM.ALL.
WHERE (begin_date>='01JAN2005'D and begin_date<='31DEC2005'D);
94 %attend(stop=30jun05,start=01apr05)
MPRINT(ATTEND): proc freq data=perm.all;
MPRINT(ATTEND): where begin_date between "01APR05"d and "30JUN05"d;
MPRINT(ATTEND): table location / ;
MPRINT(ATTEND): title1 "Enrollment from 01APR05 to 30JUN05";
MPRINT(ATTEND): run;
NOTE: There were 65 observations read from the data set PERM.ALL.
WHERE (begin_date>='01APR2005'D and begin_date<='30JUN2005'D);
95 %attend(nocum nopercent,stop=30jun05)
MPRINT(ATTEND): proc freq data=perm.all;
MPRINT(ATTEND): where begin_date between "01JAN05"d and "30JUN05"d;
MPRINT(ATTEND): table location / nocum nopercent;
MPRINT(ATTEND): title1 "Enrollment from 01JAN05 to 30JUN05";
MPRINT(ATTEND): run;
NOTE: There were 137 observations read from the data set PERM.ALL.
WHERE (begin_date>='01JAN2005'D and begin_date<='30JUN2005'D);
96 %attend()
MPRINT(ATTEND): proc freq data=perm.all;
MPRINT(ATTEND): where begin_date between "01JAN05"d and "31DEC05"d;
MPRINT(ATTEND): table location / ;
MPRINT(ATTEND): title1 "Enrollment from 01JAN05 to 31DEC05";
MPRINT(ATTEND): run;
NOTE: There were 299 observations read from the data set PERM.ALL.
WHERE (begin_date>='01JAN2005'D and begin_date<='31DEC2005'D);
4-26 Module 4 Defining and Executing Macro Programs
66
These steps permit rapid development and debugging because they isolate syntax and logic at the
SAS code level from the syntax and logic at the macro level.
Module 4 Summary
Define and call a simple macro.
Control macro storage.
Define and call macros with parameters.
Describe the difference between positional and
keyword parameters.
69
4.2 Macro Parameters 4-27
Session 2 Summary
Used macro functions to manipulate macro variables
and expressions.
Defined and called simple, positional, and keyword
macro definitions.
Stored macro definition and source code permanently.
70
Module 5 Creating and Resolving
Macro Variables During Execution
Objectives
Create macro variables during DATA step execution.
Describe the difference between the SYMPUT routine
and the %LET statement.
Reference macro variables indirectly.
Create a series of macro variables using the SYMPUT
routine.
Create macro variables during PROC SQL execution.
Store several values in one macro variable using the
SQL procedure.
10
Many applications require macro variables to have values based on data values, programming logic, or
expressions.
5.1 Creating Macro Variables in the DATA Step 5-3
13
Symbol Table
Symbol Table
data revenue; crsnum 3
set perm.all end=final;
where course_number=3;
total+1;
if paid='Y' then paidup+1;
if final then do;
put total= paidup=;
if paidup<total then do;
%let foot=Some Fees Due;
end;
else do;
%let foot=All Students Paid;
end;
end;
run;
16
Quick Quiz
Can a macro variable have more than one value assigned
to it at one time?
Example:
Symbol Table
%let crsnum=3;
crsnum 3
%let crsnum=8;
crsnum 8
17
Example:
%let crsnum=3; Symbol Table
%let crsnum=8; crsnum 3
18
5.1 Creating Macro Variables in the DATA Step 5-5
19
end;
else do;
%let foot=All Students Paid;
end;
end;
run;
21
%LET statements execute at word scanning time, while SAS statements other than macro
statements are sent to the compiler.
end;
else do; Nothing in this DATA step
affects the value of FOOT.
end;
It remains
end;
run; All Students Paid.
22
5.1 Creating Macro Variables in the DATA Step 5-7
– static values
– dynamic (data dependent) values
– dynamic (data dependent) names.
Symbol Table
CALL
CALL SYMPUT(macro-variable,
SYMPUT(macro-variable, text);
text);
24
SAS Output
Paid Status for Course 3
Quick Quiz
What is the value of &foot after execution of this DATA
step?
data _null_;
call symput('foot','Some Fees Due');
%let foot=All Students Paid;
run;
29
5.1 Creating Macro Variables in the DATA Step 5-11
Program Flow
The statements are tokenized.
Compiler
Macro Processor
Word data
data
Scanner _null_
_null_
;;
call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
Input %let
%let foot=All
foot=All Students
Students Paid;
Paid;
run;
run;
Stack
30
Program Flow
The %LET statement is submitted.
data
data _null_;
_null_;
Compiler call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
%%
let
let Macro Processor
foot
foot
==
Word All
All
Students
Scanner Students
Paid
Paid
;;
run;
run;
Input
31
Stack
Program Flow
When a macro trigger is encountered, it is passed to the
macro processor for evaluation.
data
data _null_;
_null_;
Compiler call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
Macro Processor
foot
foot
==
%let
%let
Word All
All
Students
Scanner Students
Paid
Paid
;;
Input run;
run;
32
Stack
5-12 Module 5 Creating and Resolving Macro Variables During Execution
Program Flow
The macro processor requests tokens until a semicolon
is encountered, then executes the macro statement.
data
data _null_;
_null_;
Compiler call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
Macro Processor
%let
%let foot=All
foot=All Students
Students Paid;
Paid;
Word
Scanner
Symbol Table
foot All Students Paid
Input run;
run;
33
Stack
Program Flow
Tokenization resumes.
data
data _null_;
_null_;
Compiler call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
Macro Processor
run;
Word run;
Scanner
Symbol Table
foot All Students Paid
Input
34
Stack
Program Flow
The compiler receives a step boundary and executes the
DATA step. The SYMPUT routine updates the value
of &FOOT directly in the symbol table at execution.
data
data _null_;
_null_;
Execute call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
run;
run;
Macro Processor
Word
Scanner
Symbol Table
foot Some Fees Due
Input
35
Stack
5.1 Creating Macro Variables in the DATA Step 5-13
37
CALL
CALLSYMPUT('macro-variable',
SYMPUT('macro-variable', DATA-step-variable);
DATA-step-variable);
There are extra blanks between the course title and course number, as well as extra blanks before
14 and 20 in the footnote.
5.1 Creating Macro Variables in the DATA Step 5-15
CALL
CALLSYMPUT('macro-variable',expression);
SYMPUT('macro-variable',expression);
43
The LEFT function left-justifies the value. The TRIM function removes trailing blanks. Both
functions expect character arguments. Numeric arguments cause automatic numeric-to-character
conversion, with notes written to the SAS log.
5-16 Module 5 Creating and Resolving Macro Variables During Execution
Student Activity
Open sa-symputds.sas.
Given the first row of perm.all, what is the value
for the macro variable &first ?
Course_
Obs Code Course_Title
1 C004 Database Design
%let first=course_title;
data _null_;
/* use obs= data set option to read in 1st row only */
set perm.all(obs=1);
call symput('second',trim(course_title));
run; sa-symputds
46
Symbol Table
first course_title
second Database Design
48
5.1 Creating Macro Variables in the DATA Step 5-17
49
5-18 Module 5 Creating and Resolving Macro Variables During Execution
symput5
50
The PUT function returns the character string formed by writing a value with a specified format.
You can use the PUT function to
• format the result of a numeric expression
• perform explicit numeric-to-character conversion.
General form of the PUT function:
PUT(source, format)
CALL
CALL SYMPUTX(macro-variable,
SYMPUTX(macro-variable,expression);
expression);
52
symput7
55
56
57
5.1 Creating Macro Variables in the DATA Step 5-21
Course_
Obs Code Location ENROLLMENT PERCENT
Student Activity
Open sa-symputx.sas.
Submit the code and review the initial results in the
GRAPH1 window.
Issue a macro call that changes the stop value to
31Jul2005.
Review the results in the GRAPH1 window.
59
If you add a %put _user_; statement into the macro definition, you see the values that are currently in
the local symbol table for the macro variables created in this macro definition.
%put _user_;
GLOBAL STUDENTS 299
GLOBAL START 01Jan2005
GLOBAL STOP 31Dec2005
GLOBAL AVERAGE 24.9
5.2 Indirect References to Macro Variables 5-23
Student_Name Paid
63
64
5-24 Module 5 Creating and Resolving Macro Variables During Execution
%let crs=3;
proc print data=perm.register noobs;
where course_number=&crs;
var student_name paid;
title1 "Roster for Course &crs";
run;
65
66
%let crs=3;
data _null_;
set perm.schedule;
where course_number=&crs;
call symput('teacher',trim(teacher));
Output
run; from Proc Print
proc print data=perm.register noobs;
where course_number=&crs;
var student_name paid;
title1 "Roster for Course &crs";
title2 "Taught by &teacher";
run; indirect1
67
5.2 Indirect References to Macro Variables 5-25
68
Symbol Table
Variable Value
TEACH1 Hallis, Dr. George
TEACH2 Wickam, Dr. Alice
TEACH3 Forest, Mr. Peter
… …
69
CALL
CALLSYMPUT(expression1,expression2);
SYMPUT(expression1,expression2);
CALL
CALLSYMPUTX(expression1,expression2);
SYMPUTX(expression1,expression2);
71
72
Quick Quiz
How many macro variables are created with the program
named sa-symput?
Listing of PERM.COURSES Data Set
Course_
Obs Code Course_Title Days Fee
data _null_;
set perm.courses;
call symput(course_code,trim(course_title));
run;
sa-symput
73
5.2 Indirect References to Macro Variables 5-27
Macro Processor
Word run;
run;
Scanner
Symbol Table
Input %put
%put _user_;
_user_;
Stack SYSDAY Tuesday
76
Partial PDV
Course_
Teacher
Number
$
N
20
8
Symbol Table
SYSDAY Tuesday
77
Symbol Table
SYSDAY Tuesday
78
5-28 Module 5 Creating and Resolving Macro Variables During Execution
Symbol Table
SYSDAY Tuesday
79
TEACH1 Hallis, Dr. George
Partial PDV
Course_
Teacher
Number
$
N
20
8
1 Hallis, Dr. George
Symbol Table
SYSDAY Tuesday
80
TEACH1 Hallis, Dr. George
Symbol Table
SYSDAY Tuesday
81
TEACH1 Hallis, Dr. George
5.2 Indirect References to Macro Variables 5-29
Symbol Table
SYSDAY Tuesday
TEACH1 Hallis, Dr. George
82
TEACH2 Wickam, Dr. Alice
Symbol Table
SYSDAY Tuesday
TEACH1 Hallis, Dr. George
83
TEACH2 Wickam, Dr. Alice
Compiler
Macro Processor
Word %%
put
Scanner put
Symbol Table
_user_;
Input _user_;
SYSDAY Tuesday
Stack TEACH1 Hallis, Dr. George
84
TEACH2 Wickam, Dr. Alice
5-30 Module 5 Creating and Resolving Macro Variables During Execution
Compiler
Macro Processor
Word %put
%put _user_;
_user_;
Scanner
Symbol Table
Input
SYSDAY Tuesday
Stack TEACH1 Hallis, Dr. George
85
TEACH2 Wickam, Dr. Alice
86
%let crs=2;
proc print data=perm.register noobs;
where course_number=&crs;
var student_name paid;
title1 "Roster for Course &crs";
title2 "Taught by &teach2";
run; indirect3
87
5.2 Indirect References to Macro Variables 5-31
88
Student Activity
Open sa-indirect.sas.
Submit the code and review the results.
Change the value of crs in the %LET statement to 8.
What macro variable reference can we substitute for
&teach3, in order to make one change to &crs
and have the value of teacher populated or referenced
indirectly?
89
92
Student_Name Paid
1st scan
2nd scan
(only occurs when
&& is encountered)
94
5.2 Indirect References to Macro Variables 5-33
WARNING
2nd scan
(only occurs when
&& is encountered)
95
WARNING
2nd scan
(only occurs when
&& is encountered)
96
WARNING
97
5-34 Module 5 Creating and Resolving Macro Variables During Execution
Symbol Table
Variable Value
CRS 3
TEACH1 Hallis, Dr. George
TEACH2 Wickam, Dr. Alice
TEACH3 Forest, Mr. Peter
… …
Scan sequence:
98
Quick Quiz
Given the following symbol table, what does
&&teach&crs resolve to?
Symbol Table
Variable Value
CRS 2
TEACH1 Hallis, Dr. George
TEACH2 Wickam, Dr. Alice
TEACH3 Forest, Mr. Peter
99
5.2 Indirect References to Macro Variables 5-35
%let crs=3;
proc print data=perm.register noobs;
where course_number=&crs;
var student_name paid;
title1 "Roster for Course &crs";
title2 "Taught by &&teach&crs";
run;
Partial SAS Log
65 %let crs=3;
66 proc print data=perm.register noobs;
67 where course_number=&crs;
SYMBOLGEN: Macro variable CRS resolves to 3
68 var student_name paid;
SYMBOLGEN: Macro variable CRS resolves to 3
69 title1 "Roster for Course &crs";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable CRS resolves to 3
SYMBOLGEN: Macro variable TEACH3 resolves to Forest, Mr. Peter
70 title2 "Taught by &&teach&crs";
71 run;
SAS Output
Roster for Course 3
Taught by Forest, Mr. Peter
Student_Name Paid
SELECT
SELECTcol1,
col1,col2,
col2, ......INTO
INTO:mvar1,
:mvar1, :mvar2,...
:mvar2,...
FROM
FROMtable-expression
table-expression
WHERE
WHEREwhere-expression
where-expression
other
otherclauses;
clauses;
107
SELECT
SELECTcol1,
col1,......INTO
INTO:mvar1
:mvar1--:mvarn,...
:mvarn,...
FROM table-expression
FROM table-expression
WHERE
WHEREwhere-expression
where-expression
other
otherclauses;
clauses;
109
110
5.3 Creating Macro Variables in SQL 5-39
SAS Output
SQL result
Course
Code Begin
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
C003 01/10/2006
C004 01/24/2006
C005 02/28/2006
C006 03/28/2006
5-40 Module 5 Creating and Resolving Macro Variables During Execution
SELECT Statement
Output
SQL result Partial SAS Log
Course_Code Begin_Date
53 %put &crsid1, &date1;
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
C003, 01/10/2006
C003 01/10/2006
54 %put &crsid2, &date2;
C004 01/24/2006
C004, 01/24/2006
C005 02/28/2006
C006 03/28/2006
113
SELECT
SELECTcol1,
col1,......
INTO
INTO:mvar
:mvarSEPARATED
SEPARATEDBYBY’delimiter’,
’delimiter’,......
FROM table-expression
FROM table-expression
WHERE
WHEREwhere-expression
where-expression
other
otherclauses;
clauses;
114
Module 5 Summary
Create macro variables during DATA step execution.
Describe the difference between the SYMPUT routine
and the %LET statement.
Reference macro variables indirectly.
Create a series of macro variables using the SYMPUT
routine.
Create macro variables during PROC SQL execution.
Store several values in one macro variable using the
SQL procedure.
119
Course_
Obs Code Course_Title Days Fee
120
5-42 Module 5 Creating and Resolving Macro Variables During Execution
data _null_;
set perm.courses;
call symputx(course_code, course_title);
run;
indirect5
121
122
Scan sequence:
reference &&&crsid
124
Quick Quiz
Given the following symbol table, what does &&&CRSID
resolve to?
Symbol Table
Variable Value
CRSID C006
C001 Basic Telecommunications
C002 Structured Query Language
C003 Local Area Networks
C004 Database Design
C005 Artificial Intelligence
C006 Computer Aided Design
125
126
5-44 Module 5 Creating and Resolving Macro Variables During Execution
127
5.3 Creating Macro Variables in SQL 5-45
Objectives
Execute macro language statements iteratively.
Generate SAS code iteratively.
Conditionally process SAS code within a macro
program.
Monitor macro execution.
Insert entire steps, entire statements, and partial
statements into a SAS program.
Explain the difference between global and local symbol
tables.
Describe how the macro processor decides which
symbol table to use.
Describe the concept of nested macros and the
hierarchy of symbol tables.
2
Simple Loops
Many macro applications require iterative processing.
The iterative %DO statement can repeatedly
execute macro language statements
%DO
%DO index-variable=start
index-variable=start %TO
%TOstop
stop<%BY
<%BY increment>;
increment>;
text
text
%END;
%END;
4
6.1 Iterative Processing 6-3
Simple Loops
%DO and %END statements are valid only inside a
macro definition.
Index-variable is a macro variable.
Index-variable is created in the local symbol table if it
does not already exist in an existing symbol table.
Start, stop, and increment values can be any valid
macro expressions that resolve to integers.
%BY clause is optional (default increment is 1).
Simple Loops
Text can be
constant text
macro statements
macro calls.
6
6-4 Module 6 Utilizing Macro Language Statements
Simple Loops
Example: Create a numbered series of macro variables.
Display each macro variable in the SAS log by
repeatedly executing %PUT within a macro loop.
data _null_;
set perm.schedule end=no_more;
call symputx('teach'||left(_n_),teacher);
if no_more then call symputx('count',_n_);
run;
%macro putloop;
%do i=1 %to &count;
%put TEACH&i is &&teach&i;
%end;
%mend putloop;
loop1
No code is sent to the compiler when the macro executes. The %PUT statements are executed by
the macro processor.
Quick Quiz
Given the data below, what is the name and the value of
the first macro variable created?
Listing of PERM.SCHEDULE
data _null_;
set perm.schedule end=no_more;
call symput('teach'||left(_n_),(trim(teacher)));
if no_more then call symput('count',_n_);
run;
8
6.1 Iterative Processing 6-5
Simple Loops
Partial SAS Log
12 %putloop
TEACH1 is Hallis, Dr. George
TEACH2 is Wickam, Dr. Alice
TEACH3 is Forest, Mr. Peter
TEACH4 is Tally, Ms. Julia
TEACH5 is Hallis, Dr. George
TEACH6 is Berthan, Ms. Judy
TEACH7 is Hallis, Dr. George
TEACH8 is Wickam, Dr. Alice
TEACH9 is Forest, Mr. Peter
TEACH10 is Tally, Ms. Julia
TEACH11 is Tally, Ms. Julia
TEACH12 is Berthan, Ms. Judy
TEACH13 is Hallis, Dr. George
TEACH14 is Wickam, Dr. Alice
TEACH15 is Forest, Mr. Peter
TEACH16 is Tally, Ms. Julia
TEACH17 is Hallis, Dr. George
TEACH18 is Berthan, Ms. Judy
10
NOTE: There were 12 observations read from the data set WORK.YEAR2001.
MLOGIC(READRAW): %DO loop index variable YEAR is now 2002; loop will iterate again.
MPRINT(READRAW): data year2002;
MPRINT(READRAW): infile "raw2002.dat";
MPRINT(READRAW): input course_code $4. location $15. begin_date date9. teacher $25.;
MPRINT(READRAW): run;
13
6-6 Module 6 Utilizing Macro Language Statements
15
Quick Quiz
Given the symbol table below, what is the value of
&lib..&&dsn&i?
7 %put _user_;
GLOBAL DSN1 ALL
GLOBAL DSN2 COURSES
GLOBAL DSN3 REGISTER
GLOBAL DSN4 SCHEDULE
GLOBAL DSN5 STUDENTS
GLOBAL TOTALDSN 5
LOCAL LIB PERM
LOCAL I 4
LOCAL OBS 5
17
7 %put _user_;
GLOBAL DSN1 ALL &lib..&&dsn&i
GLOBAL DSN2 COURSES
GLOBAL DSN3 REGISTER
GLOBAL DSN4 SCHEDULE
GLOBAL DSN5 STUDENTS
PERM.&dsn4
GLOBAL TOTALDSN 5
LOCAL LIB PERM
LOCAL I 4 PERM.SCHEDULE
LOCAL OBS 5
18
19
6-8 Module 6 Utilizing Macro Language Statements
NOTE: There were 18 observations read from the data set PERM.SCHEDULE.
NOTE: The data set WORK.BOSTON has 6 observations and 5 variables.
NOTE: The data set WORK.DALLAS has 6 observations and 5 variables.
NOTE: The data set WORK.SEATTLE has 6 observations and 5 variables.
21
22
6.1 Iterative Processing 6-9
23
Quick Quiz
Given the symbol table below, what is the value of
&&site&i?
7 %put _user_;
GLOBAL SITE1 Boston
GLOBAL SITE2 Dallas
GLOBAL SITE3 Seattle
GLOBAL COUNT 3
LOCAL I 1
25
6-10 Module 6 Utilizing Macro Language Statements
NOTE: There were 18 observations read from the data set PERM.SCHEDULE.
NOTE: The data set WORK.BOSTON has 6 observations and 5 variables.
NOTE: The data set WORK.DALLAS has 6 observations and 5 variables.
NOTE: The data set WORK.SEATTLE has 6 observations and 5 variables.
27
%DO
%DO %WHILE(expression);
%WHILE(expression);
text
text
%END;
%END;
32
6.1 Iterative Processing 6-11
%DO
%DO %UNTIL(expression);
%UNTIL(expression);
text
text
%END;
%END;
33
executes at least once.
34
35
6-12 Module 6 Utilizing Macro Language Statements
36
37
6.2 Conditional Processing 6-13
49
Conditional Processing
You can perform conditional execution with %IF-%THEN
and %ELSE statements.
General form of %IF-%THEN and %ELSE statements:
%IF
%IF expression
expression %THEN
%THENtext;
text;
%ELSE
%ELSEtext;
text;
Conditional Processing
The text following keywords %THEN and %ELSE can be
a macro programming statement
constant text
an expression
a macro call.
52
CAUTION
Compound expressions can be specified using the AND and OR operators. Do not precede
these keywords with %.
6.2 Conditional Processing 6-15
parameter values
macro termination.
OPTIONS
OPTIONSMLOGIC;
MLOGIC;
OPTIONS
OPTIONSNOMLOGIC;
NOMLOGIC;
53
%macro weekly;
proc means data=perm.all maxdec=0 sum;
where put(begin_date,monyy7.)="%substr(&sysdate9,3,7)"
and begin_date le "&sysdate9"d;
class begin_date location course_title;
var fee;
title "Revenue for Courses as of &sysdate9";
run;
%mend weekly;
54
55
6-16 Module 6 Utilizing Macro Language Statements
56
58
Student Activity
Submit the following program. Will this code execute
without errors?
%macro printit(print=Yes);
%if &print=Yes %then
proc print data=perm.schedule;
title "Print the Schedule data set";
run;
%mend printit;
%printit( )
59
6.2 Conditional Processing 6-17
Conditional Processing
Use %DO and %END statements following %THEN or
%ELSE to generate text that contains semicolons.
%IF
%IF expression
expression %THEN
%THEN %DO;
%DO;
statement;
statement;statement;
statement;......
%END;
%END;
%ELSE
%ELSE %DO;
%DO;
statement;
statement;statement;
statement;......
%END;
%END;
61
%macro reports;
%include 'daily.sas';
%if &sysday=Friday %then %do;
%include 'weekly.sas';
%end;
%mend reports;
cond03
63
6-18 Module 6 Utilizing Macro Language Statements
%INCLUDE
%INCLUDEfile-specification
file-specification<<//SOURCE2
SOURCE2>;
>;
64
If SOURCE2 is not specified in the %INCLUDE statement, the setting of the SAS system option
SOURCE2 controls whether the inserted SAS code is displayed.
Student Activity
Submit the following program.
%macro attend(crs);
proc print data=perm.all;
%if &crs= %then %do;
title1 "All Courses";
%end;
%else %do;
title1 "Course &crs only";
where course_code="&crs";
%end;
run;
%mend attend;
%attend(C003)
sa-title
67
NOTE: There were 162 observations read from the data set PERM.ALL.
WHERE (begin_date>='01JUL2005'D and begin_date<='31DEC2005'D);
71
NOTE: There were 50 observations read from the data set PERM.ALL.
WHERE (begin_date>='01JAN2005'D and begin_date<='31DEC2005'D) and
(course_code='C003');
%else %do;
where paid = 'N';
keep student_name course_code
begin_date totalfee latechg;
latechg=fee*1.10;
%end;
if location='Boston' then totalfee=fee*1.06;
else if location='Seattle' then totalfee=fee*1.025;
else if location='Dallas' then totalfee=fee*1.05;
run;
%mend choice;
%choice(PAID)
%choice(OWED)
73 Macro comparisons are case-sensitive. cond05
6.2 Conditional Processing 6-21
NOTE: There were 327 observations read from the data set PERM.ALL.
WHERE paid='Y';
NOTE: The data set WORK.FEES has 327 observations and 4 variables.
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.02 seconds
74
NOTE: There were 107 observations read from the data set PERM.ALL.
WHERE paid='N';
NOTE: The data set WORK.FEES has 107 observations and 5 variables.
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.02 seconds
75
NOTE: There were 434 observations read from the data set PERM.ALL.
NOTE: PROCEDURE FREQ used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds
NOTE: There were 434 observations read from the data set PERM.ALL.
NOTE: PROCEDURE FREQ used (Total process time):
real time 0.01 seconds
cpu time 0.02 seconds
78
Student Activity
Submit the program below. Will this code run without
errors?
79
6.2 Conditional Processing 6-23
Parameter Validation
Example: Validate a parameter value before generating
SAS code based on that value.
%macro courses(site);
%let site=%upcase(&site);
%if &site=DALLAS or &site=SEATTLE or &site=BOSTON
%then %do;
proc print data=perm.schedule;
where upcase(location)="&site";
title "COURSES OFFERED AT &site";
run;
%end;
%else %put Sorry, no courses taught at &site..;
%mend courses;
cond07
81
Parameter Validation
Partial SAS Log
788 %courses(Dallas)
MPRINT(COURSES): proc print data=perm.schedule;
MPRINT(COURSES): where upcase(location)="DALLAS";
MPRINT(COURSES): title "COURSES OFFERED AT DALLAS";
MPRINT(COURSES): run;
NOTE: There were 6 observations read from the data set
PERM.SCHEDULE.
WHERE UPCASE(location)='DALLAS';
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
789 %courses(LA)
Sorry, no courses taught at LA.
82
Parameter Validation
Use the %INDEX function to check the value of a macro
variable against a list of valid values.
General form of the %INDEX function:
%INDEX(argument1,
%INDEX(argument1,argument2)
argument2)
Parameter Validation
%INDEX(argument1,
%INDEX(argument1,argument2)
argument2)
macro functions
macro calls.
84
Quick Quiz
What code is placed into the log by the following macro
program?
%macro courses(site);
%if %index(DALLAS SEATTLE BOSTON,&site) > 0
%then %do;
%put Courses taught at this location.;
%end;
%else %do;
%put Sorry, no courses taught at &site..;
%end;
%mend courses;
%courses(LA)
85
Parameter Validation
Example: Parameter validation with the %INDEX function.
%macro courses(site);
%let site=%upcase(&site);
%let sitelist=*DALLAS*SEATTLE*BOSTON*;
%if %index(&sitelist,*&site*) > 0 %then %do;
proc print data=perm.schedule;
where upcase(location)="&site";
title "COURSES OFFERED AT &site";
run;
%end;
%else %do;
%put Sorry, no courses taught at &site..;
%put Valid locations are: &sitelist..;
%end;
%mend courses;
cond09
87
6.2 Conditional Processing 6-25
Parameter Validation
Partial SAS Log
762 %courses(Dallas)
MPRINT(COURSES): proc print data=perm.schedule;
MPRINT(COURSES): where upcase(location)="DALLAS";
MPRINT(COURSES): title "COURSES OFFERED AT DALLAS";
MPRINT(COURSES): run;
NOTE: There were 6 observations read from the data set
PERM.SCHEDULE.
WHERE UPCASE(location)='DALLAS';
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
763 %courses(LA)
Sorry, no courses taught at LA.
Valid locations are: *DALLAS*SEATTLE*BOSTON*.
88
Parameter Validation
Example: Modify the previous program so that the macro
variable SITELIST is data-driven.
%macro courses(site);
%let site=%upcase(&site);
proc sql noprint;
select distinct upcase(location)
into :sitelist separated by '*'
from perm.schedule;
quit;
%let sitelist=&sitelist;
%if %index(*&sitelist*,*&site*) > 0
%then %do;
. . .
cond10
89
90
6-26 Module 6 Utilizing Macro Language Statements
93
94
6.3 Global and Local Symbol Table 6-27
Variable Value
SYSDATE 23FEB04
SYSDAY Monday
SYSVER 9.1
. .
. .
. .
uservar1 value1
uservar2 value2
96
97
%GLOBAL
%GLOBAL macrovar1
macrovar1macrovar2
macrovar2......;;
98
6-28 Module 6 Utilizing Macro Language Statements
99
100
Variable Value
parameter1 value1
parameter2 value2
. .
. .
. .
uservar1 value1
uservar2 value2
101
6.3 Global and Local Symbol Table 6-29
102
%LOCAL
%LOCAL macrovar1
macrovar1macrovar2
macrovar2......;;
104
105
6-30 Module 6 Utilizing Macro Language Statements
CALL
CALL SYMPUTX(macro-variable,
SYMPUTX(macro-variable,text,
text,<scope>);
<scope>);
106
Macro Processor
Quick Quiz
In the following program, is the macro variable i global or
local?
%let i=5;
%macro quiz;
%do i=1 %to 3;
%put Hi mom.;
%end;
%mend quiz;
%quiz
109
%macro outer;
%local x; Create a global macro variable X.
%let x=1;
%inner
%mend outer; %let x=0;
%macro inner;
%local y; Global Table
%let y=&x; X 0
%mend inner;
111
Global Table
%outer
X 0
Global Table
%macro outer; X 0
%local x;
%let x=1;
%inner OUTER Local Table
%mend outer;
%macro inner; X 1
%local y;
%let y=&x; INNER Local Table
%mend inner;
Y
113
114
Global Table
%macro outer; X 0
%local x;
%let x=1; OUTER Local Table
%inner
%mend outer; X 1
%macro inner;
%local y;
%let y=&x;
%mend inner;
115
6.3 Global and Local Symbol Table 6-33
Global Table
%macro outer; X 0
%local x;
%let x=1;
%inner
%mend outer;
%macro inner;
%local y;
%let y=&x;
%mend inner;
116
117
%macro check(comp);
data subset;
set perm.students;
where student_company="&comp";
run;
%numobs(work,subset)
%if &num>0 %then %do;
proc print data=subset noobs;
var student_name city_state;
title "&num Students from &comp";
run;
%end;
%else %put No students from &comp..;
%mend check;
%check(Reston Railway) Global Table
119
num 0
check Local Table
num 14
check Local Table
Student Activity
%macro numobs(lib,dsn); Why is NUM
%*global num; declared global in
%let num=0; the NUMOBS
proc sql noprint;
select (nobs-delobs) into :num macro?
from dictionary.tables
where libname="%upcase(&lib)" Submit the
and memname="%upcase(&dsn)"; program
quit; sa-symbol1.sas.
%let num=# Notice the
%mend numobs;
%macro check(comp); %global num;
data subset; statement is now
set perm.students; a comment.
where student_company="&comp";
run; What happens?
%numobs(work,subset)
%if &num>0 %then %do;
proc print data=subset noobs;
var student_name city_state;
title "&num Students from &comp";
run;
%end;
%else %put No students from &comp..;
123 %mend check; sa-symbol1
Student Activity
%macro numobs(lib,dsn); Omit the * from
%global num; the %global num;
%let num=0; statement.
proc sql noprint;
select (nobs-delobs) into :num
from dictionary.tables Submit the
where libname="%upcase(&lib)" program
and memname="%upcase(&dsn)"; sa-symbol1.sas
quit; again.
%let num=#
%mend numobs;
%macro check(comp); What happens?
data subset;
set perm.students;
where student_company="&comp";
run;
%numobs(work,subset)
%if &num>0 %then %do;
proc print data=subset noobs;
var student_name city_state;
title "&num Students from &comp";
run;
%end;
%else %put No students from &comp..;
125 %mend check; symbol1
6-36 Module 6 Utilizing Macro Language Statements
%macro check(comp);
data subset;
set perm.students;
where student_company="&comp";
NUMOBS has finished
run; execution. Therefore, its
%numobs(work,subset)
%if &num>0 %then %do; local symbol table is
proc print data=subset noobs; deleted.
var student_name city_state;
title "&num Students from &comp";
run;
%end;
%else %put No students from &comp..;
%mend check;
%check(Reston Railway) Global Table
126
%macro check(comp);
data subset; The values of &num
set perm.students;
where student_company="Reston Railway"; and &comp are
run; substituted into the
%numobs(work,subset)
%if 14>0 %then %do; program.
proc print data=subset noobs;
var student_name city_state;
title "14 Students from Reston Railway";
run;
%end;
%else %put No students from Reston Railway.;
%mend check;
%check(Reston Railway) Global Table
num 14
CHECK Local Table
NOTE: There were 14 observations read from the data set PERM.STUDENTS.
WHERE student_company='Reston Railway';
NOTE: The data set WORK.SUBSET has 14 observations and 3 variables.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds
NOTE: There were 14 observations read from the data set WORK.SUBSET.
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
128
6.3 Global and Local Symbol Table 6-37
NOTE: There were 0 observations read from the data set PERM.STUDENTS.
WHERE student_company='Raston Railway';
NOTE: The data set WORK.SUBSET has 0 observations and 3 variables.
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
129
Module 6 Summary
Conditionally process SAS code within a macro
program.
Monitor macro execution.
Insert entire steps, entire statements, and partial
statements into a SAS program.
Execute macro language statements iteratively.
Generate SAS code iteratively.
Explain the difference between global and local symbol
tables.
Describe how the macro processor decides which
symbol table to use.
Describe the concept of nested macros and the
hierarchy of symbol tables.
132
Appendix A Exercises and Solutions
Session 1
Module 2 Exercises
1. Using Automatic Macro Variables
Open the babbit program shown below into the Editor window.
options nocenter;
proc print data=perm.all noobs label uniform;
where student_name contains 'Babbit';
by student_name student_company;
var course_title begin_date location teacher;
title 'Courses Taken by Selected Students:';
title2 'Those with Babbit in Their Name';
run;
Add a footnote that displays today's date (use an automatic macro variable) using this text:
Report Created on date
Submit the program and examine the output it creates.
2. Displaying Automatic Macro Variables
Use the %PUT statement to display the values of the SYSDAY and SYSVER macro variables in the
SAS log.
3. Defining and Using Macro Variables
a. Open the babbit program shown below into the Editor window. Submit the program and
examine the output it creates.
options nocenter;
proc print data=perm.all noobs label uniform;
where student_name contains 'Babbit';
by student_name student_company;
var course_title begin_date location teacher;
title 'Courses Taken by Selected Students:';
title2 'Those with Babbit in Their Name';
run;
b. Edit the program to change the search pattern in the WHERE statement and TITLE2 statement
from Babbit to Ba and resubmit. Examine the output.
c. Modify the program so that the two occurrences of Ba are replaced by references to the macro
variable PATTERN. Precede the program with a %LET statement to assign the value Ba to
PATTERN. Submit the program. It produces the same output as before.
d. Submit a %PUT statement to display the value of all user-defined macro variables including
PATTERN.
0 Session 1 A-3
After-Class Exercises
1. Macro Variable References
Open the program countloc shown below into the Editor window.
title;
proc sql;
select location,n(location) label='Count'
from perm.schedule,perm.register
where schedule.course_number=
register.course_number
group by location;
quit;
a. Submit the program. The SELECT statement creates a listing from two SAS data sets (tables) that
are merged (joined) by the common variable course_number. The GROUP BY clause
reduces the listing to distinct values of location. The N function counts the number of
observations that are within distinct values of the GROUP BY variable.
A-4 Appendix A Exercises and Solutions
Precede the program with %LET statements that initialize these macro variables to the values
currently in the program. Submit the program and compare the listing with the one created earlier.
It should produce the same output as before.
c. Edit the program to change the values of the macro variables to create a listing from the
perm.students and perm.register data sets that shows the distribution of the
city_state variable. The two data sets have the student_name variable in common (join
variable).
d. Save the program for an after-class exercise tomorrow. Name the program AfterClass1.
2. Using the %SYMDEL Statement
a. Use the %SYMDEL statement to remove the FREQVAR and JOINVAR macro variables from the
global symbol table.
b. Display a list of all the user-defined macro variables that are currently in the global symbol table.
1) Do you see the macro variables you deleted in this list?
2) Do you think it is possible to delete all of the user-defined macro variables from the global
symbol table?
0 Session 1 A-5
b. There are four students whose name contains the text string Ba: Bill Babbit, Vincent Baker,
Ellen Bates, and Barbara Turner.
proc print data=perm.all noobs label uniform;
where student_name contains 'Ba';
by student_name student_company;
var course_title begin_date location teacher;
title 'Courses Taken by Selected Students';
title2 'Those with Ba in Their Name';
run;
Partial Output
Courses Taken by Selected Students
Those with Ba in Their Name
c. The macro variable PATTERN should contain the text string Ba without any surrounding quotes.
To resolve the macro variable in the WHERE and TITLE2 statement, change the single quotes to
double quotes.
%let pattern=Ba;
options nocenter;
proc print data=perm.all noobs label uniform;
where student_name contains "&pattern";
by student_name student_company;
var course_title begin_date location teacher;
title 'Courses Taken by Selected Students';
title2 "Those with &pattern in Their Name";
run;
d. A %PUT statement can verify that the macro variable PATTERN contains the text string Ba. The
_USER_ argument displays the values of all user-defined macro variables:
%put _user_;
Partial SAS Log
108 %put _user_;
GLOBAL PATTERN Ba
b. The references to the input data set names in the WHERE clause are followed by two periods,
the first acting as the macro variable name delimiter and the second received by the compiler as
part of the two-level column name.
%let table1=schedule;
%let table2=register;
%let joinvar=course_number;
%let freqvar=location;
title;
proc sql;
select &freqvar,n(&freqvar) label='Count'
from perm.&table1,perm.&table2
where &table1..&joinvar=&table2..&joinvar
group by &freqvar;
quit;
SAS Output
Location Count
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
Boston 150
Dallas 133
Seattle 151
c. The only changes required are new values assigned to the macro variables in the %LET
statements.
%let table1=students;
%let table2=register;
%let joinvar=student_name;
%let freqvar=city_state;
title;
proc sql;
select &freqvar,n(&freqvar) label='Count'
from perm.&table1,perm.&table2
where &table1..&joinvar=&table2..&joinvar
group by &freqvar;
quit;
A-10 Appendix A Exercises and Solutions
Partial Output
City,State Count
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
Akron, OH 5
Albany, NY 2
Allentown, PA 3
Annapolis, MD 7
Atlanta, GA 7
Austin, TX 3
Bethesda, MD 1
Birmingham, AL 2
Bozeman, MT 10
Brea, CA 2
Buena Park, CA 1
Chicago, IL 71
Chicago, IN 2
Cincinnati, OH 1
Cleveland, OH 3
Columbia, MD 4
Columbus, OH 8
Costa Mesa, CA 9
Cupertino, CA 2
Dallas, TX 8
d. Select File Ö Save As from your pull-down menu. Type the name of the program,
AfterClass1 in the File Name field.
Session 2
If you are starting a new SAS session, remember to submit a LIBNAME statement.
libname perm '.'; *Virtual lab;
libname perm 'C:\SAS_Education\LWMACR'; *working on local PC;
Module 3 Exercises
1. Using Macro Functions
a. Submit the program sortsched shown below to create the work.sorted data set:
b. Open the program dictcols shown below into the Editor window and submit it. This program
uses a PROC SQL dictionary table to display the variables in a specified data set.
title "Variables in PERM.SCHEDULE";
proc sql;
select name, type, length
from dictionary.columns
where libname="PERM" and
memname="SCHEDULE";
quit;
c. Add a %LET statement to assign the value perm.schedule to a macro variable named DSN.
Use the new macro variable in the TITLE statement. Use one or more macro functions to separate
the value of DSN into the library reference and the data set name for substitution into the
WHERE clause. Submit the modified program. You should get the same report.
d. Change the %LET statement to assign the value perm.courses to the DSN macro variable.
Submit the modified program to see the new report.
e. Change the %LET statement to assign the value of the automatic macro variable SYSLAST to the
DSN macro variable. Submit the modified program to see the new report. What was the value of
SYSLAST? When was that data set created?
A-12 Appendix A Exercises and Solutions
Module 4 Exercises
1. Defining and Calling a Macro
Open the printnum program into the Editor window. The printnum program contains this PROC
PRINT step:
proc print data=perm.all label noobs n;
where course_number=3;
var student_name student_company;
title "Enrollment for Course 3";
run;
a. Change the hardcoded 3 in the WHERE and TITLE statements to reference the macro variable
NUM. Convert this program into a macro. Submit the macro definition to compile the macro.
b. Submit a %LET statement to assign the value 8 to the macro variable NUM. Then, call the macro
defined in the previous step.
c. Activate the appropriate system options to display the source code received by the SAS compiler
2. Defining and Using Macro Parameters
Open the printnum program into the Editor window or modify the program you created in
Exercise 1.
proc print data=perm.all label noobs n;
where course_number=3;
var student_name student_company;
title "Enrollment for Course 3";
run;
a. Change the hardcoded 3 in WHERE and TITLE statements to reference the macro variable NUM.
Convert this program into a macro with a positional parameter. Select a name for the parameter
based on the macro variable references in the program. Submit the macro definition to compile
the macro.
b. Activate the appropriate system option to display the source code received by the SAS compiler.
Call the macro defined in the previous step with a value of 8 for the parameter.
0 Session 2 A-13
After-Class Exercises
1. Using Keyword Parameters
Open the AfterClass1 program saved during a previous session.
a. Convert the program into a macro with keyword parameters. Specify the default values for the
parameters according to the values in the original query from the countloc program. Submit the
macro definition to compile the macro.
b. Call the macro with the default values supplied in the macro definition.
c. Call the macro again. Modify the values in your macro call in order to execute the query for the
values specified below.
Table1 students
Joinvar student_name
Freqvar city_state
2. Using Macro Quoting Functions
a. Retrieve the babbit program shown below into the Editor window. Change the name Babbit in
the WHERE statement and the TITLE2 statement to O'Savio. Remember to change the quotes
to double quotes.
Submit the modified program.
options nocenter;
proc print data=perm.all noobs label uniform;
where student_name contains 'Babbit';
by student_name student_company;
var course_title begin_date location teacher;
title 'Courses Taken by Selected Students:';
title2 'Those with Babbit in Their Name';
run;
b. Modify the program so that the two occurrences of O'Savio are replaced by references to the
macro variable PATTERN. Precede the program with a %LET statement to assign the value
O'Savio to PATTERN. Add a %PUT statement to display the value of the PATTERN macro
variable.
Submit the program. It should produce the same output as before.
A-14 Appendix A Exercises and Solutions
b. Open the dictcols program shown below into the Editor window and submit it. This program
uses a PROC SQL dictionary table to display the variables in a specified data set.
title "Variables in PERM.SCHEDULE";
proc sql;
select name, type, length
from dictionary.columns
where libname="PERM" and
memname="SCHEDULE";
quit;
c. The %SCAN function can divide the value of the macro variable DSN into parts. The default
delimiter set will work for this example; however, the single applicable delimiter, the period (.),
can be specified as the third argument to %SCAN.
The %UPCASE function may be required, because the values of LIBNAME and MEMNAME in the
DICTIONARY.COLUMNS table are in uppercase.
%let dsn=perm.schedule;
%let libref=%upcase(%scan(&dsn,1,.));
%let dsname=%upcase(%scan(&dsn,2,.));
title "Variables in %upcase(&dsn)";
proc sql;
select name, type, length
from dictionary.columns
where libname="&libref" and
memname="&dsname";
quit;
SAS Output
Variables in PERM.SCHEDULE
Column Column
Column Name Type Length
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
Course_Number num 8
Course_Code char 4
Location char 15
Begin_Date num 8
Teacher char 20
0 Session 2 A-15
Alternate Solution
%let dsn=perm.schedule;
title "Variables in %upcase(&dsn)";
proc sql;
select name, type, length
from dictionary.columns
where libname="%upcase(%scan(&dsn,1,.))" and
memname="%upcase(%scan(&dsn,2,.))";
quit;
SAS Output
Variables in PERM.SCHEDULE
Column Column
Column Name Type Length
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
Course_Number num 8
Course_Code char 4
Location char 15
Begin_Date num 8
Teacher char 20
d. Changing the value of the macro variable DSN automatically changes which data set is analyzed.
%let dsn=perm.courses;
%let libref=%upcase(%scan(&dsn,1,.));
%let dsname=%upcase(%scan(&dsn,2,.));
title "Variables in %upcase(&dsn)";
proc sql;
select name, type, length
from dictionary.columns
where libname="&libref" and
memname="&dsname";
quit;
SAS Output
Variables in PERM.COURSES
Column Column
Column Name Type Length
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
Course_Code char 4
Course_Title char 25
Days num 8
Fee num 8
A-16 Appendix A Exercises and Solutions
e. The value of the macro variable SYSLAST is assigned as the value of the macro variable DSN,
so the work.sorted data set is analyzed. The work.sorted data set was created in the
PROC SORT step above.
%let dsn=&syslast;
%let libref=%upcase(%scan(&dsn,1,.));
%let dsname=%upcase(%scan(&dsn,2,.));
title "Variables in %upcase(&dsn)";
proc sql;
select name, type, length
from dictionary.columns
where libname="&libref" and
memname="&dsname";
quit;
SAS Output
Variables in WORK.SORTED
Column Column
Column Name Type Length
ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ
Course_Number num 8
Course_Code char 4
Location char 15
Begin_Date num 8
Teacher char 20
b. Correct the program using %BQUOTE so that the space is retained between the first and last
initials.
__S F_________________________________________________________________________
%let finit=S;
%let minit=%bquote( );
%let linit=F;
%put &finit&minit&linit;
0 Session 2 A-17
Partial Output
Enrollment for Course 8
Student Name Company
N = 20
c. To display the code received by the SAS compiler, including all resolved macro variable
references, use the MPRINT system option. To track the resolution of macro variables, use the
SYMBOLGEN system option.
options mprint symbolgen;
%printnum
Partial SAS Log
182 options mprint symbolgen;
183 %printnum
MPRINT(PRINTNUM): proc print data=perm.all label noobs n;
SYMBOLGEN: Macro variable NUM resolves to 8
MPRINT(PRINTNUM): where course_number=8;
MPRINT(PRINTNUM): var student_name student_company;
SYMBOLGEN: Macro variable NUM resolves to 8
MPRINT(PRINTNUM): title "Enrollment for Course 8";
MPRINT(PRINTNUM): run;
NOTE: There were 20 observations read from the dataset PERM.ALL.
WHERE course_number=8;
NOTE: PROCEDURE PRINT used:
real time 11.64 seconds
cpu time 0.14 seconds
0 Session 2 A-19
Partial Output
Enrollment for Course 8
N = 20
c. The macro definition does not need to be resubmitted with each macro call. The macro call does
not end with a semicolon.
%prtrost(10)
Partial SAS Log
MPRINT(PRTROST): proc print data=perm.all label noobs n;
MPRINT(PRTROST): where course_number=10;
MPRINT(PRTROST): var student_name student_company;
MPRINT(PRTROST): title "Enrollment for Course 10";
MPRINT(PRTROST): run;
NOTE: There were 23 observations read from the dataset PERM.ALL.
WHERE course_number=10;
NOTE: PROCEDURE PRINT used:
real time 11.44 seconds
cpu time 0.17 seconds
d. When you define keyword parameters, an equal sign (=) must follow the name of each parameter.
A default value for each parameter can be specified following the equal sign.
%macro prtrost(num=1);
proc print data=perm.all label noobs n;
where course_number=#
var student_name student_company;
title "Enrollment for Course &num";
run;
%mend prtrost;
0 Session 2 A-21
e. To assign a value to a keyword parameter, specify the name of the parameter followed by an equal
sign (=), followed by the desired value.
%prtrost(num=8)
Partial SAS Log
18 %prtrost(num=8)
MPRINT(PRTROST): proc print data=perm.all label noobs n;
MPRINT(PRTROST): where course_number=8;
MPRINT(PRTROST): var student_name student_company;
MPRINT(PRTROST): title "Enrollment for Course 8";
MPRINT(PRTROST): run;
NOTE: There were 20 observations read from the dataset PERM.ALL.
WHERE course_number=8;
NOTE: PROCEDURE PRINT used:
real time 10.51 seconds
cpu time 0.12 seconds
f. To request that all default parameter values be used, follow the macro call with an empty set of
parentheses.
%prtrost()
Partial SAS Log
19 %prtrost()
MPRINT(PRTROST): proc print data=perm.all label noobs n;
MPRINT(PRTROST): where course_number=1;
MPRINT(PRTROST): var student_name student_company;
MPRINT(PRTROST): title "Enrollment for Course 1";
MPRINT(PRTROST): run;
NOTE: There were 23 observations read from the dataset PERM.ALL.
WHERE course_number=1;
NOTE: PROCEDURE PRINT used:
real time 13.20 seconds
cpu time 0.15 seconds
b. Call the macro with the default values supplied in the macro definition.
%freq_report( )
c. Call the macro again. Modify the values in your macro call in order to execute the query for the
values specified below.
Table1 students
Joinvar student_name
Freqvar city_state
%freq_report(table1=students,joinvar=student_name,freqvar=city_state)
2. Using Macro Quoting Functions (solution program s-bquote2.sas)
a. Double quotes are needed to handle the embedded single quotes (apostrophe) in the name
O'Savio when it is used in the literal text.
proc print data=perm.all noobs label uniform;
where student_name contains "O'Savio";
by student_name student_company;
var course_title begin_date location teacher;
title 'Courses Taken by Selected Students:';
title2 "Those with O'Savio in Their Name";
run;
b. The %BQUOTE function is needed to handle the apostrophe in the name O'Savio when
assigning it as the value of a macro variable.
%let pattern=%BQUOTE(O'Savio);
Session 3
If you are starting a new SAS session, remember to submit a LIBNAME statement.
libname perm '.'; *Virtual lab;
libname perm 'C:\SAS_Education\LWMACR'; *working on local PC;
Module 5 Exercises
1. Creating Macro Variables with the SYMPUT Routine
a. Reset the system option DATE|NODATE to NODATE using the OPTIONS statement:
options nodate;
You also may want to activate the SYMBOLGEN option.
b. Write a DATA step that creates a macro variable named DATE from the perm.schedule data
set that contains the begin_date variable. This date is the starting date for each course. This
macro variable's value should be the begin_date in MMDDYY10. format, where
course_number=15.
c. Insert the value of the macro variable DATE into a TITLE statement:
title "Roster for Course Offered on &date";
d. Verify that the text of the title resolved correctly by printing the roster for course_number=15
found in the perm.register data set or by opening the TITLES window.
e. Modify the DATA step so that the macro variable DATE has a value that reflects the
WORDDATE20. format (month dd, year).
Verify the text of the title again. Make sure there are no extra blanks in the title.
2. Creating Multiple Macro Variables with the SYMPUT Routine
a. The perm.schedule data set contains the variable begin_date, which contains the starting
date of each course. Use a DATA step to create a series of macro variables named START1
through STARTn, one for each course offered. The value of each START macro variable should
be the starting date of the corresponding class in the MMDDYY10. format.
b. Open the prtrost program shown below into the Editor window. Modify the TITLE statement
so the series of Xs is replaced with an indirect macro variable reference to one of the START
variables based on the current value of CRS. Submit the modified program.
%let crs=4;
proc print data=perm.all noobs n;
where course_number=&crs;
var student_name student_company;
title1 "Roster for Course &crs";
title2 "Beginning on XXXXX";
run;
A-24 Appendix A Exercises and Solutions
After-Class Exercises
1. Generating Multiple Steps with Macro Loops
a. Define a macro with positional parameters that can print a series of reports, each report containing
observations having a particular value for a selected variable. For example, because the
perm.schedule data set contains six distinct values for course_code, the macro should
produce six reports, one for each distinct value of course_code.
The macro should generate six separate PROC PRINT steps for each distinct value of
course_code.
proc print data=perm.schedule noobs;
where course_code="C001";
title "Listing of PERM.SCHEDULE Data Set";
title2 "for COURSE_CODE=C001";
run;
Parameters for the macro are
• data set to be printed
• variables used for subsetting.
b. Use the macro to generate a separate report for each value of course_code in the
perm.schedule data set.
c. Use the macro to generate a separate report for each value of location in the
perm.schedule data set.
0 Session 3 A-25
data _null_;
set perm.schedule;
call symput('StartDate'||trim(left(course_number)),
put(begin_date,mmddyy10.));
run;
a. Display the values of the newly created macro variables in the SAS log.
b. Create a temporary data set named outstand containing the students in the perm.register
data set who have not yet paid their registration fee. Create a new variable that indicates the
starting date for the corresponding course number. Print the outstand data set.
The INPUT function is needed to convert character values of macro variables retrieved
by the SYMGET function into numeric SAS data values.
4. Macro Variable Storage and Resolution (Optional)
Determine the type, length, and value of the DATA step variables in the program below.
%let var1=cat;
%let var2=3;
data test;
length s1 s4 s5 $ 3;
call symput('var3','dog');
r1="&var1";
r2=&var2;
r3="&var3";
s1=symget('var1');
s2=symget('var2');
s3=input(symget('var2'),2.);
s4=symget('var3');
s5=symget('var'||left(r2));
run;
A-26 Appendix A Exercises and Solutions
R1
R2
R3
S1
S2
S3
S4
S5
Hint: Mimic the behavior of SAS by making three passes through the program: word scanning,
compilation, and execution.
Hint: Draw a symbol table, updating it as each macro variable is created and assigned a value.
b. Write a DATA step that creates a macro variable named DATE from the perm.schedule data
set that contains the begin_date variable. This date is the starting date for each course. This
macro variable's value should be the begin_date in MMDDYY10. format, where
course_number=15.
The PUT function converts the numeric SAS date value returned by BEGIN_DATE into a
character string representing the course start date in mm/dd/yyyy form.
data _null_;
set perm.schedule;
where course_num=15;
call symput('date',put(begin_date,mmddyy10.));
run;
c. Insert the value of the macro variable DATE into a TITLE statement:
title "Roster for Course Offered on &date";
d. This PROC PRINT step should display the desired title:
proc print data=perm.register noobs n;
where course_number=15;
title "Roster for Course Offered on &date";
run;
Course_
Student_Name Number Paid
N = 24
A-28 Appendix A Exercises and Solutions
e. The WORDDATE20. format typically generates leading blanks. Use the TRIM and LEFT
functions to remove them.
options nodate symbolgen;
data _null_;
set perm.schedule;
where course_num=15;
call symput('date', trim(left(put(today(),
worddate20.))));
run;
Partial Output
Roster for Course Offered on January 10, 2006
Course_
Student_Name Number Paid
2. Creating Multiple Macro Variables with the SYMPUT Routine (solution program s-indir.sas)
a. Concatenating the text START with the value of the CRSNUM variable specifies the name of
each macro variable. Since the CRSNUM variable is numeric, the LEFT function is required to
remove the leading blanks introduced by the automatic numeric-to-character conversion. The
%PUT statement displays the names and values of all user-created macro variables.
data _null_;
set perm.schedule;
call symput('start'||trim(left(course_number)),
put(begin_date,mmddyy10.));
run;
%put _user_;
b. Because each macro variable that contains a course date has a common root at the start of its
name (START) and a suffix that corresponds to the value of the CRS macro variable, two
ampersands are used in front of the complete reference.
options symbolgen;
%let crs=4;
proc print data=perm.all noobs n;
where course_number=&crs;
var student_name student_company;
title1 "Roster for Course &crs";
title2 "Beginning on &&start&crs";
run;
Partial Output
Roster for Course 4
Beginning on 1/25/2005
Student_Name Student_Company
b. Because the series of macro variables has a common root (START) and a suffix that corresponds
to the value of the NUM macro variable, two ampersands are used in front of the completed
reference.
%let num=4;
Partial Output
Roster for Course 4 Beginning on 01/25/2005
Student_Name Student_Company
c. (Optional) The NUMROWS macro variable stores how many records will be returned by the
query. This is the same as the number of macro variables in each series.
proc sql noprint;
select count(*)
into :numrows
from perm.schedule;
%let numrows=&numrows;
select begin_date format=mmddyy10.
into :date1 - :date&numrows
from perm.schedule;
quit;
%let num=4;
proc print data=perm.all noobs n;
where course_number = #
var student_name student_company;
title1 "Roster for Course &num";
title2 "Starting on &&date&num";
run;
A-32 Appendix A Exercises and Solutions
data _null_;
set unique end=final;
call symputx('value'||left(_n_),&var);
if final then call symputx('count',_n_);
run;
b. The macro call to generate the separate report for each training center location in the
perm.schedule data set is
%printall(perm.schedule,course_code)
Partial SAS Log
MPRINT(PRINTALL): proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL): where COURSE_CODE="C001";
MPRINT(PRINTALL): title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL): title2 "for COURSE_CODE=C001";
MPRINT(PRINTALL): run;
NOTE: There were 3 observations read from the data set PERM.SCHEDULE.
WHERE COURSE_CODE='C001';
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.02 seconds
cpu time 0.00 seconds
MPRINT(PRINTALL): proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL): where COURSE_CODE="C002";
MPRINT(PRINTALL): title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL): title2 "for COURSE_CODE=C002";
MPRINT(PRINTALL): run;
NOTE: There were 3 observations read from the data set PERM.SCHEDULE.
WHERE COURSE_CODE='C002';
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
NOTE: There were 3 observations read from the data set PERM.SCHEDULE.
WHERE COURSE_CODE='C005';
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
c. The macro call to generate a separate report for each class duration in the perm.courses data
set.
%printall(perm.schedule,location)
MLOGIC(PRINTALL): %DO loop index variable I is now 2; loop will iterate again.
MPRINT(PRINTALL): proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL): where LOCATION="Dallas";
MPRINT(PRINTALL): title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL): title2 "for LOCATION=Dallas";
MPRINT(PRINTALL): run;
NOTE: There were 6 observations read from the data set PERM.SCHEDULE.
WHERE LOCATION='Dallas';
NOTE: PROCEDURE PRINT used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds
a. The _USER_ argument in the %PUT statement displays all user-created macro variables.
%put _user_;
Partial SAS Log
GLOBAL STARTDATE17 02/28/2006
GLOBAL STARTDATE16 01/24/2006
GLOBAL DSN perm.courses
GLOBAL VARS days fee
GLOBAL STARTDATE8 06/14/2005
GLOBAL STARTDATE18 03/28/2006
GLOBAL STARTDATE9 07/19/2005
GLOBAL CRSNUM 3
GLOBAL DATE 01/11/2005
GLOBAL STARTDATE4 01/25/2005
GLOBAL STARTDATE5 03/01/2005
GLOBAL STARTDATE6 04/05/2005
GLOBAL NUMPAID 14
GLOBAL STARTDATE7 05/24/2005
GLOBAL STARTDATE11 09/20/2005
GLOBAL NUMSTU 20
GLOBAL CRSNAME Local Area Networks
GLOBAL DUE $3,900
GLOBAL STARTDATE10 08/16/2005
GLOBAL NUM 8
GLOBAL STARTDATE1 10/26/2004
GLOBAL STARTDATE13 11/15/2005
GLOBAL STARTDATE2 12/07/2004
GLOBAL STARTDATE12 10/04/2005
GLOBAL STARTDATE3 01/11/2005
GLOBAL STARTDATE15 01/10/2006
GLOBAL STARTDATE14 12/06/2005
The order in which the macro variables are displayed may differ from the order in which
they were created.
A-36 Appendix A Exercises and Solutions
b. The correct date can be obtained by appending the value of the course_number variable as a
suffix to START to identify the corresponding macro variable name. The retrieved (character)
value should be converted to a numeric SAS date value with a permanently assigned format.
data outstand;
set perm.register;
where paid='N';
begin=input(symget('start'||
left(course_number)),mmddyy10.);
format begin date9.;
run;
Course_
Obs Student_Name Number begin
Execution
The values of each variable are determined during execution of the program. It is at this time that the
CALL SYMPUT statement creates the macro variable VAR3 so that its value is available for retrieval
by the SYMGET function later in the DATA step.
R1 and R2 Hardcoded values are assigned.
R3 The reference &VAR3 is a text string during execution, so this is also a hardcoded
value.
S1 Value obtained from the symbol table.
S2 Value obtained from the symbol tables does not fill allotment of 200 characters;
there are 199 trailing blanks.
S3 The first two characters obtained from the symbol table are converted into a
numeric value using the 2. informat.
S4 and S5 Same value obtained from the symbol table since each SYMGET argument results
in the character string var3. Macro variable VAR3 was created earlier in the
execution of the DATA step.
Session 4
If you are starting a new SAS session, remember to submit a LIBNAME statement.
libname perm '.'; *Virtual lab;
libname perm 'C:\SAS_Education\LWMACR'; *working on local PC;
Module 6 Exercises
1. Using Macro Loops
Open the printnum program shown below into the Editor window.
proc print data=perm.all label noobs n;
where course_number=3;
var student_name student_company;
title "Enrollment for Course 3";
run;
Define a macro program that generates a separate listing for each of the courses in the perm.all
data set. The values of course_number range from 1 to 18.
%paid(2)
b. Modify the macro so it submits the PROC PRINT step only if the CRSNUM parameter has a
value between 1 and 18. If the CRSNUM value is out of range, the macro should write this
message to the SAS log:
Course Number must be between 1 and 18.
Supplied value was: x
c. Resubmit the macro definition and call the macro using both valid and invalid parameter values.
A-40 Appendix A Exercises and Solutions
d. Modify the macro to support a second positional parameter named STATUS. Add this statement
after the WHERE statement:
where also paid="&status";
At the beginning of the macro, extract the first character of STATUS and store it in uppercase.
Alter the macro so that the PROC PRINT step can be submitted only when the STATUS
parameter begins with Y or N.
Resubmit the macro definition and call the macro using both valid and invalid values for
STATUS.
3. Creating Multiple Symbol Tables
Open the nested program shown below into the Editor window.
%macro prtrost(num=1);
data _null_;
call symput('today',
trim(left(put(today(),mmddyy10.))));
run;
%prtrost
Partial SAS Log
MPRINT(PRTROST): proc print data=perm.all label noobs n;
MPRINT(PRTROST): where course_number=1;
MPRINT(PRTROST): var student_name student_company;
MPRINT(PRTROST): title1 "Enrollment for Course 1";
MPRINT(PRTROST): run;
NOTE: There were 23 observations read from the dataset PERM.ALL.
WHERE course_number=1;
NOTE: PROCEDURE PRINT used:
real time 0.07 seconds
cpu time 0.07 seconds
%paid(2)
A-42 Appendix A Exercises and Solutions
b. To define a valid range, the %IF expression must contain two comparisons connected with the
AND operator. Each message line requires a separate %PUT statement.
%macro paid(crsnum);
%if &crsnum >=1 and &crsnum <= 18 %then %do;
proc print data=perm.register label noobs n;
where course_number=&crsnum;
title "Fee Status for Course &crsnum";
run;
%end;
%else %do;
%put Course Number must be between 1 and 18;
%put Supplied Value was: &crsnum;
%end;
%mend paid;
%paid(2)
%paid(20)
c. Resubmit the macro definition and call the macro.
Partial SAS Log
MLOGIC(PAID): Ending execution.
222 %paid(20)
MLOGIC(PAID): Beginning execution.
MLOGIC(PAID): Parameter CRSNUM has value 20
MLOGIC(PAID): %IF condition &crsnum >=1 and &crsnum <= 18 is FALSE
MLOGIC(PAID): %PUT Course Number must be between 1 and 18
Course Number must be between 1 and 18
MLOGIC(PAID): %PUT Supplied Value was: &crsnum
Supplied Value was: 20
MLOGIC(PAID): Ending execution.
0 Session 4 A-43
d. The %UPCASE and %SUBSTR functions are used to extract the first character of the parameter
value and translate it to uppercase. The additional condition based on STATUS can be
implemented using the AND operator with the previous CRSNUM validation expression or with
nested %IF-%THEN statements.
%macro paid(crsnum,status);
%let status1=%upcase(%substr(&status,1,1));
%if &status1=Y or &status1=N %then %do;
%if &crsnum >= 1 and &crsnum <= 18 %then %do;
proc print data=perm.register label n noobs;
var student_name paid;
where course_number=&crsnum;
where also paid="&status1";
title "Fee Status for Course &crsnum";
run;
%end;
%else %do;
%put Course Number must be between 1 and 18;
%put Supplied Value was: &crsnum;
%end;
%end;
%else %do;
%put Status must begin with Y or N;
%put Supplied value was: &status;
%end;
%mend paid;
%paid(2,Y)
%paid(2,no)
%paid(2,?)
Partial SAS Log
246 %paid(2,no)
MLOGIC(PAID): Beginning execution.
MLOGIC(PAID): Parameter CRSNUM has value 2
MLOGIC(PAID): Parameter STATUS has value no
MLOGIC(PAID): %LET (variable name is STATUS1)
MLOGIC(PAID): %IF condition &status1=Y or &status1=N is TRUE
MLOGIC(PAID): %IF condition &crsnum >= 1 and &crsnum <= 18 is TRUE
MPRINT(PAID): proc print data=perm.register label n noobs;
MPRINT(PAID): var student_name paid;
MPRINT(PAID): where course_number=2;
MPRINT(PAID): where also paid="N";
NOTE: Where clause has been augmented.
MPRINT(PAID): title "Fee Status for Course 2";
MPRINT(PAID): run;
NOTE: There were 8 observations read from the dataset PERM.REGISTER.
WHERE (course_number=2) and (paid='N');
NOTE: PROCEDURE PRINT used:
real time 2.40 seconds
cpu time 0.03 seconds
247 %paid(2,?)
MLOGIC(PAID): Beginning execution.
MLOGIC(PAID): Parameter CRSNUM has value 2
MLOGIC(PAID): Parameter STATUS has value ?
MLOGIC(PAID): %LET (variable name is STATUS1)
MLOGIC(PAID): %IF condition &status1=Y or &status1=N is FALSE
MLOGIC(PAID): %PUT Status must begin with Y or N
Status must begin with Y or N
MLOGIC(PAID): %PUT Supplied value was: &status
Supplied value was: ?
MLOGIC(PAID): Ending execution
%macro prtrost(num=1);
%local today;
%datemvar(fmt=mmddyy10.);
proc print data=perm.all label noobs n;
where course_number=#
var student_name student_company city_state;
title1 "Enrollment for Course &num as of &today";
run;
%mend prtrost;
%prtrost(num=8)
Appendix B SAS Programming Flow
and Macro Variable Retrieval in the
DATA Step
B.1 Program Flow................................................................................................................. B-2
SYMBOL TABLE
WORD SCANNER
MACRO
PROCESSOR
MACRO LIBRARY
INPUT STACK
3
B.2 Retrieving Macro Variables in the DATA Step B-3
Objectives
Obtain the value of a macro variable during DATA step
execution.
Describe the difference between the SYMGET
function and macro variable references.
Review
create macro
variables
%LET
6
B-4 Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
Review
%LET &macvar
Review
word
scanning %LET &macvar
time
Review
word
scanning %LET &macvar
time
execution
time CALL SYMPUT
9
B.2 Retrieving Macro Variables in the DATA Step B-5
word
scanning %LET &macvar
time
execution
time CALL SYMPUT SYMGET(macvar)
10
Symbol Table
Program Data Vector
DATA Step
Variables SYMGET
11
SYMGET(macro-variable)
SYMGET(macro-variable)
12
Question: When does SYMGET retrieve the value of the macro variable?
B-6 Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
Symbol Table
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(’teach’||left(course_number));
run;
symget1
15
B.2 Retrieving Macro Variables in the DATA Step B-7
Word run;
Macro Processor
run;
Scanner
Symbol Table
Input
teach1 Hallis, Dr. George
Stack teach2 Wickam, Dr. Alice
teach3 Forest, Mr. Peter
16
Partial PDV
Initialize PDV
Course_ to missing.
Number Teacher
N $
8 20
.
Symbol Table
Symbol Table
Symbol Table
Symbol Table
Symbol Table
Symbol Table
Symbol Table
Partial PDV
Processing continues until
Course_ SAS has read all rows in the
Number Teacher perm.register data
N $ set.
8 20
Symbol Table
Course_
Obs Student_Name Number teacher
25
Student Activity
Submit the programs. Would the following pieces of code
have given you the same results?
dataChange
_null_;your seat indicator to Yes or No.
set perm.schedule;
call symput(’teach’||left(course_number),trim(teacher));
run;
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(’teach’||left(course_number));
run;
sa-append2
data teachers2;
merge perm.register
perm.schedule(keep=course_number teacher);
by course_number;
run;
26