Sas Macros
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.
SAS Macro Language Course Notes
Copyright 2005 by SAS Institute Inc., Cary, NC 27513, USA. All rights reserved. Printed in the
United States of America. No part of this publication may be reproduced, stored in a retrieval system,
or transmitted, in any form or by any means, electronic, mechanical, photocopying, or otherwise, without
the prior written permission of the publisher, SAS Institute Inc.
Book code E70039, course code LWMACR, prepared date 07Sep05.
Table of Contents
Course Description ...................................................................................................................... vi
Prerequisites ...............................................................................................................................vii
Module 1
1.1
1.2
1.3
Course Data....................................................................................................................1-18
Module 2
2.1
2.2
2.3
2.4
2.5
Module 3
3.1
3.2
Module 4
4.1
4.2
Module 5
5.1
iii
iv
5.2
5.3
Module 6
6.1
Iterative Processing..........................................................................................................6-2
6.2
6.3
Appendix A
vi
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
A full curriculum of general and statistical instructor-based training is available
at any of the Institutes training facilities. Institute instructors can also provide
on-site training.
For information on other courses in the curriculum, contact the SAS Education
Division at 1-800-333-7660, or send e-mail to [email protected]. You can also
find this information on the Web at support.sas.com/training/ as well as in the
Training Course Catalog.
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 [email protected]. 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.
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
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 SAS data set options such as DROP=, KEEP=, and OBS=
create and use SAS date values, including SAS date constants
execute Base SAS procedures such as SORT, PRINT, CONTENTS, MEANS, FREQ, TABULATE,
and CHART.
1.2
Program Flow..................................................................................................................1-8
1.3
1-2
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-3
1-4
12
Conditional Processing
Example: Generate a detailed report on a daily basis.
Generate an additional report every Friday,
summarizing data on a weekly basis.
Daily report
Is it
Friday?
Yes
Repetitive Processing
Example: Generate a similar report each year from
2003 to 2005.
Data-Driven Applications
Example: Create a separate subset of a data set for each
unique value of a selected variable.
16
1-5
1-6
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.
18
Student Activity
Substitute &sysdate9 for 25AUG2004 and submit the
following program:
19
1-7
1-8
22
Program Flow
Input
InputStack
Stack
SUBMIT
Command
data
data new;
new;
set
set perm.mast;
perm.mast;
bonus=wage*0.1;
bonus=wage*0.1;
run;
run;
proc
proc print;
print;
run;
run;
23
Stored
Process
Batch or
Noninteractive
Submission
%STPBEGIN;
%STPBEGIN;
proc
proc print
print data=new;
data=new;
run;
run;
proc
means
data=new;
proc means data=new;
run;
run;
%STPEND;
%STPEND;
//SYSIN
//SYSIN DD
DD **
options
options nodate;
nodate;
proc
proc sql;
sql;
select
select **
from
from perm.mast;
perm.mast;
quit;
quit;
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.
Word
Scanner
Input
Stack
data
data
new
new
;;
set
set perm.mast;
perm.mast;
bonus=wage*0.1;
bonus=wage*0.1;
run;
run;
proc
proc print;
print;
run;
run;
24
Program Flow
The word scanner passes the tokens, one at a time, to
the appropriate compiler, as the compiler demands.
Compiler
Word Scanner
Input Stack
data
data new;
new;
set
set
perm
perm
..
mast
mast
;;
bonus=wage*0.1;
bonus=wage*0.1;
run;
run;
proc
proc print;
print;
run;
run;
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-9
1-10
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.
Examples:
'Any text'
"Any text"
28
Number Tokens
Number tokens can be
integer numbers, including SAS date constants
floating point numbers, containing a decimal point
and/or exponent.
Examples:
29
3
3.
3.5
-3.5
01jan2002d
5E8
7.2E-4
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
a blank after a token.
Blanks
are not tokens
delimit tokens.
The maximum length of a token is 32,767 characters.
33
1-11
1-12
Example
Input Stack
var x1-x10
Tokens
1.
2.
3.
4.
5.
6.
var
x1
x10
z
;
34
Example
Input Stack
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-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
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.
The word scanner passes macro triggers to the
macro processor, which
requests additional tokens as necessary
performs the action indicated.
42
Macro Statements
Macro statements
begin with a percent sign (%) followed by a name token
end with a semicolon
represent macro triggers
are executed by the macro processor.
43
%PUT
%PUT text;
text;
44
45
Program Flow
The %PUT statement is submitted.
Compiler
Macro Processor
Word
Scanner
Input
Stack
%put
%put Hi
Hi Mom!;
Mom!;
46
Program Flow
The statement is tokenized.
Compiler
Word
Scanner
Input
Stack
47
Macro Processor
%%
put
put
Hi
Hi
Mom
Mom
!!
;;
1-15
1-16
Program Flow
When a macro trigger is encountered, it is passed to the
macro processor for evaluation.
Compiler
Word
Scanner
Macro Processor
%put
%put
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
Scanner
%put
%put Hi
Hi Mom!;
Mom!;
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
Input
Stack
50
1
%put "Hi Mom";
"Hi Mom"
51
1-17
1-18
Description
Number of Observations
courses
schedule
18
students
207
register
434
all
434
These data sets are stored in a SAS data library with a libref of perm.
PERM.COURSES
DATA
V9
Tuesday, May 30,
2000 04:21:30 PM
Monday, June 12,
2000 10:39:41 AM
Last Modified
Protection
Data Set Type
Label
Data Representation
Encoding
Observations
Variables
Indexes
Observation Length
6
4
0
48
Deleted Observations
Compressed
Sorted
NO
NO
WINDOWS_32
Default
4096
2
1
84
6
0
C:\workshop\winsas\macr\courses.sas7bdat
8.0000M0
WIN_NT
Variable
Type
Len
1
2
3
4
Course_Code
Course_Title
Days
Fee
Char
Char
Num
Num
4
25
8
8
Format
1.
DOLLAR5.
Informat
Label
1.
DOLLAR5.
Course Code
Description
Course Length
Course Fee
Listing of PERM.COURSES
Obs
1
2
3
4
5
6
Course_
Code
C001
C002
C003
C004
C005
C006
Course_Title
Basic Telecommunications
Structured Query Language
Local Area Networks
Database Design
Artificial Intelligence
Computer Aided Design
Days
3
4
3
2
2
5
Fee
$795
$1150
$650
$375
$400
$1600
1-19
1-20
PERM.SCHEDULE
DATA
V9
Monday, July 12,
2004 04:29:52 PM
Monday, July 12,
2004 04:29:52 PM
Last Modified
Protection
Data Set Type
Label
Data Representation
Encoding
Observations
Variables
Indexes
Observation Length
18
5
0
56
Deleted Observations
Compressed
Sorted
NO
NO
WINDOWS_32
wlatin1 Western
(Windows)
8192
1
1
145
18
0
C:\workshop\winsas\macr\schedule.sas7bdat
9.0101B3
XP_PRO
Variable
Type
Len
Format
Informat
Label
4
2
1
3
5
Begin_Date
Course_Code
Course_Number
Location
Teacher
Num
Char
Num
Char
Char
8
4
8
15
20
DATE9.
DATE7.
2.
2.
Begin
Course Code
Course Number
Location
Instructor
Obs
1
2
3
4
5
6
7
Course_
Number
1
2
3
4
5
6
7
Course_
Code
C001
C002
C003
C004
C005
C006
C001
Location
Seattle
Dallas
Boston
Seattle
Dallas
Boston
Dallas
Begin_
Date
26OCT2004
07DEC2004
11JAN2005
25JAN2005
01MAR2005
05APR2005
24MAY2005
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Hallis, Dr. George
Berthan, Ms. Judy
Hallis, Dr. George
PERM.STUDENTS
DATA
V9
Tuesday, May 30,
2000 04:21:31 PM
Monday, June 12,
2000 10:39:11 AM
Last Modified
Protection
Data Set Type
Label
Data Representation
Encoding
Observations
Variables
Indexes
Observation Length
207
3
0
85
Deleted Observations
Compressed
Sorted
NO
NO
WINDOWS_32
Default
8192
4
1
95
80
0
C:\workshop\winsas\macr\students.sas7bdat
8.0000M0
WIN_NT
Variable
Type
Len
3
2
1
City_State
Student_Company
Student_Name
Char
Char
Char
20
40
25
Label
City,State
Company
Student Name
Student_Name
Student_Company
City_State
Eastman Developers
Reston Railway
Special Services
Department of Defense
Assoc. of Realtors
Reston Railway
National Credit Corp.
Snowing Petroleum
Reston Railway
Jost Hardware Inc.
Hospital Nurses Association
Reston Railway
Deerfield, IL
Chicago, IL
Oak Brook, IL
Bethesda, MD
Chicago, IL
Chicago, IL
Chicago, IL
New Orleans, LA
Chicago, IL
Toledo, OH
Naperville, IL
Chicago, IL
1-21
1-22
PERM.REGISTER
DATA
V9
Tuesday, May 30,
2000 04:21:31 PM
Monday, June 12,
2000 10:39:54 AM
Last Modified
Protection
Data Set Type
Label
Data Representation
Encoding
Observations
Variables
Indexes
Observation Length
434
3
0
40
Deleted Observations
Compressed
Sorted
NO
NO
WINDOWS_32
Default
4096
6
1
101
68
0
C:\workshop\winsas\macr\register.sas7bdat
8.0000M0
WIN_NT
Variable
Type
Len
2
3
1
Course_Number
Paid
Student_Name
Num
Char
Char
8
1
25
Obs
1
2
3
4
5
6
7
8
9
10
11
12
Format
Informat
Label
2.
2.
Course Number
Paid Status
Student Name
1
1
1
1
1
1
1
1
1
1
1
1
Paid
Y
N
Y
Y
Y
Y
Y
N
Y
Y
Y
Y
1-23
1-24
PERM.ALL
DATA
V9
Friday, July 23,
2004 02:53:26 PM
Friday, July 23,
2004 02:53:26 PM
Last Modified
Protection
Data Set Type
Label
Data Representation
Encoding
Observations
Variables
Indexes
Observation Length
434
12
0
184
Deleted Observations
Compressed
Sorted
NO
YES
WINDOWS_32
wlatin1 Western (Windows)
16384
6
1
88
76
0
C:\workshop\winsas\macr\all.sas7bdat
9.0101B3
XP_PRO
Variable
Type
Len
Format
Informat
Label
Begin_Date
City_State
Course_Code
Course_Number
Course_Title
Days
Fee
Location
Paid
Student_Company
Student_Name
Teacher
Num
Char
Char
Num
Char
Num
Num
Char
Char
Char
Char
Char
8
20
4
8
25
8
8
15
1
40
25
20
DATE9.
DATE7.
2.
2.
1.
DOLLAR5.
1.
DOLLAR5.
Begin
City,State
Course Code
Course Number
Description
Course Length
Course Fee
Location
Paid Status
Company
Student Name
Instructor
Sort Information
Sortedby
Validated
Character Set
Student_Name Course_Code
YES
ANSI
Obs
1
2
3
4
5
Obs
Begin_
Date
1
2
3
4
5
16AUG2005
05APR2005
06DEC2005
26OCT2004
01MAR2005
Obs
1
2
3
4
5
Course_
Number
Student_Name
Days
2
5
4
3
2
10
6
14
1
5
Teacher
$375
$1600
$1150
$795
$400
Y
N
N
Y
Y
C004
C006
C002
C001
C005
Location
Dallas
Boston
Seattle
Seattle
Dallas
Database Design
Computer Aided Design
Structured Query Language
Basic Telecommunications
Artificial Intelligence
Student_Company
Eastman Developers
Eastman Developers
Reston Railway
Special Services
Special Services
Student Activity
Examine the contents of the perm library.
Submit the program:
60
Course_
Code
Course_Title
Fee
Paid
City_State
Deerfield, IL
Deerfield, IL
Chicago, IL
Oak Brook, IL
Oak Brook, IL
1-25
1-26
Module 1 Summary
61
2.2
2.3
2.4
2.5
2-2
Macro Variables
Macro variables store text, including
complete or partial SAS steps
complete or partial SAS statements.
Macro variables are referred to as symbolic variables
because SAS programs can reference macro variables
as symbols for additional program text.
Automatic
Variables
Automatic
Variables
User-Defined
Variables
Macro Variables
Macro variables in the global symbol table
are global in scope (available any time)
have a minimum length of 0 characters (null value)
have a maximum length of 65,534 (64K) characters
store numeric tokens as character strings.
2-3
2-4
Description
SYSDATE
SYSDATE9
SYSDAY
SYSTIME
SYSSCP
SYSVER
10
Description
SYSLAST
SYSPARM
11
12
_automatic_;
AFDSID 0
AFDSNAME
AFLIB
AFSTR1
AFSTR2
FSPBDV
SYSBUFFR
SYSCC 3000
SYSCHARWIDTH 1
SYSCMD
SYSDATE 05FEB04
SYSDATE9 05FEB2004
2-5
2-6
Student Activity
%put _automatic_;
14
18
2-7
2-8
Compiler
Macro Processor
Word
Scanner
Input
Stack
Symbol Table
%put
%put Today
Today is
is &sysday;
&sysday;
SYSDAY
SYSLAST
Tuesday
_NULL_
19
Input
Stack
%put
%put
Today
Today is
is &sysday;
&sysday;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
20
Input
Stack
21
%put
%put Today
Today is
is &sysday;
&sysday;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
Input
Stack
%put
%put Today
Today is
is &sysday;
&sysday;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
22
Input
Stack
%put
%put Today
Today is
is Tuesday;
Tuesday;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
23
Input
Stack
24
%put
%put Today
Today is
is Tuesday;
Tuesday;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
2-9
2-10
Dallas
05JAN2000
975
Compiler
Macro Processor
Word
Scanner
Input
Stack
proc
proc print
print data=perm.all;
data=perm.all;
title
title "Today
"Today is
is &sysday";
&sysday";
run;
run;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
27
Compiler
Word
Scanner
Input
Stack
28
proc
proc print
print data=perm.all;
data=perm.all;
title
title
Macro Processor
""
Today
Today
is
is
Symbol Table
run;
run;
&sysday";
&sysday";
SYSDAY
SYSLAST
Tuesday
_NULL_
Compiler
Word
Scanner
Input
Stack
proc
proc print
print data=perm.all;
data=perm.all;
title
title
Macro Processor
&sysday
&sysday
""
Today
Today
is
is
Symbol Table
run;
run;
";
";
SYSDAY
SYSLAST
Tuesday
_NULL_
29
Compiler
Word
Scanner
Input
Stack
proc
proc print
print data=perm.all;
data=perm.all;
title
title
""
Today
Today
is
is
Macro Processor
&sysday
&sysday
Symbol Table
run;
run;
";
";
SYSDAY
SYSLAST
Tuesday
_NULL_
30
Compiler
Word
Scanner
Input
Stack
31
proc
proc print
print data=perm.all;
data=perm.all;
title
title
Macro Processor
""
Today
Today
is
is
Symbol Table
run;
run;
Tuesday";
Tuesday";
SYSDAY
SYSLAST
Tuesday
_NULL_
2-11
2-12
Compiler
Word
Scanner
Input
Stack
proc
proc print
print data=perm.all;
data=perm.all;
title
title
Macro Processor
""
Today
Today
is
is
Tuesday
Tuesday
""
Symbol Table
run;
run;
;;
SYSDAY
SYSLAST
Tuesday
_NULL_
32
proc
proc print
print data=perm.all;
data=perm.all;
title
title "Today
"Today is
is Tuesday"
Tuesday"
Macro Processor
Word
Scanner
Input
Stack
Symbol Table
run;
run;
;;
SYSDAY
SYSLAST
Tuesday
_NULL_
33
proc
proc print
print data=perm.all;
data=perm.all;
title
title "Today
"Today is
is Tuesday";
Tuesday";
Macro Processor
Word
Scanner
run;
run;
Input
Stack
34
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
Quick Quiz
What is the title if you submit the following program?
Compiler
Macro Processor
Word
Scanner
Input
Stack
proc
proc print
print data=perm.all;
data=perm.all;
title
title 'Today
'Today is
is &sysday';
&sysday';
run;
run;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
35
40
COURSE
N
Sum
Artificial Intelligence
25
$10,000
Basic Telecommunications
18
$14,310
Database Design
23
$8,625
TOTALS
133 $106,535
2-13
2-14
Unresolved Reference
Example: Reference a non-existent macro variable.
Compiler
Macro Processor
Word
Scanner
Input
Stack
proc
proc print
print data=perm.exp;
data=perm.exp;
title
title "Expenses
"Expenses for
for R&D";
R&D";
run;
run;
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
42
Unresolved Reference
The macro trigger is passed to the macro processor for
evaluation.
Compiler
proc
proc print
print data=perm.exp;
data=perm.exp;
title
title
Word
Scanner
""
Expenses
Expenses
for
for
RR
Input
Stack
run;
run;
Macro Processor
&D
&D
Symbol Table
";
";
SYSDAY
SYSLAST
Tuesday
_NULL_
43
Unresolved Reference
The macro processor writes a warning to the SAS log
when it cannot resolve a reference.
Compiler
proc
proc print
print data=perm.exp;
data=perm.exp;
title
title
Word
Scanner
""
Expenses
Expenses
for
for
RR
Input
Stack
44
run;
run;
Macro Processor
&D
&D
";
";
Symbol Table
SYSDAY
SYSLAST
Tuesday
_NULL_
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.
Compiler
proc
proc print
print data=perm.exp;
data=perm.exp;
title
title "Expenses
"Expenses for
for R&D"
R&D"
Word
Scanner
run;
run;
;;
Macro Processor
Symbol Table
Input
Stack
SYSDAY
SYSLAST
Tuesday
_NULL_
45
Word
Scanner
Input
Stack
proc
proc print
print data=&syslast;
data=&syslast;
title
title "Listing
"Listing of
of &syslast";
&syslast";
run;
run;
Symbol Table
SYSDAY
SYSLAST
Tuesday
PERM.ALL
46
proc
proc print
print data=
data=
Macro Processor
Word
Scanner
Input
Stack
47
&syslast
&syslast
;;
title
title "Listing
"Listing of
of &syslast";
&syslast";
run;
run;
Symbol Table
SYSDAY
SYSLAST
Tuesday
PERM.ALL
2-15
2-16
proc
proc print
print data=
data=
Macro Processor
Word
Scanner
Input
Stack
&syslast
;;
title
title "Listing
"Listing of
of &syslast";
&syslast";
run;
run;
Symbol Table
SYSDAY
SYSLAST
Tuesday
PERM.ALL
48
proc
proc print
print data=
data=
Macro Processor
Word
Scanner
Input
Stack
PERM.ALL;
PERM.ALL;
title
title "Listing
"Listing of
of &syslast";
&syslast";
run;
run;
Symbol Table
SYSDAY
SYSLAST
Tuesday
PERM.ALL
49
Compiler
proc
proc print
print data=PERM.ALL;
data=PERM.ALL;
Macro Processor
Word
Scanner
Input
Stack
50
Symbol Table
title
title "Listing
"Listing of
of &syslast";
&syslast";
run;
run;
SYSDAY
SYSLAST
Tuesday
PERM.ALL
proc
proc print
print data=PERM.ALL;
data=PERM.ALL;
title
title "Listing
"Listing of
of PERM.ALL";
PERM.ALL";
Word
Scanner
run;
run;
Input
Stack
Macro Processor
Symbol Table
SYSDAY
SYSLAST
Tuesday
PERM.ALL
51
2-17
2-18
55
56
56
name= Ed Norton ;
name2=' Ed Norton ';
title="Joan's Report";
start=;
sum=3+4;
total=0;
total=&total+∑
x=varlist;
&x=name age height;
57
2-19
2-20
%let
%let
%let
%let
%let
%let
%let
%let
%let
name= Ed Norton ;
name2=' Ed Norton ';
title="Joan's Report";
start=;
sum=3+4;
total=0;
total=&total+∑
x=varlist;
&x=name age height;
Value
Ed Norton
' Ed Norton '
"Joan's Report"
3+4
0+3+4
varlist
61
Quick Quiz
What is the name of the macro variable created with this
%LET statement?
Value
Ed Norton
%let name= Ed Norton ;
' Ed Norton '
%let name2= Ed Norton ;
%let title="Joans Report"; "Joan's Report"
%let start=;
3+4
%let sum=3+4;
%let total=0;
0+3+4
%let total=&total+∑
varlist
%let x=varlist;
%let &x=name age height;
Submit your answer as a text question.
62
name= Ed Norton ;
name2=' Ed Norton ';
title="Joan's Report";
start=;
sum=3+4;
total=0;
total=&total+∑
x=varlist;
&x=name age height;
macvarname=varlist
Value
Ed Norton
' Ed Norton '
"Joan's Report"
3+4
0+3+4
varlist
name age height
63
65
2-21
2-22
%let city=Dallas;
%let date=05JAN2004;
%let amount=975;
Dallas
05JAN2004
975
66
68
Dallas
05JAN2004
975
69
Quick Quiz
Global Symbol Table
CITY
DATE
AMOUNT
Dallas
05JAN2004
975
70
2-23
2-24
77
mon
78
2-25
2-26
%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
CHART DATA=PERM.Y2000JAN;
WEEK / SUMVAR=SALE;
PLOT DATA=PERM.Y2000JAN;
SALE*DAY;
83
84
2-27
2-28
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
%let
%let
%let
%let
proc
graphics=g;
year=2000;
month=jan;
var=sale;
&graphicschart data=perm.y&year&month;
10
WARNING: Apparent symbolic reference GRAPHICSCHART not resolved.
ERROR 10-205: Expecting the name of the procedure to be executed.
87
88
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;
Submit your answer as a text question.
90
92
2-29
2-30
generates
LIBNAME PERM 'SAS-data-library';
PROC GCHART DATA=PERMY2000JAN;
HBAR WEEK / SUMVAR=SALE;
RUN;
PROC GPLOT DATA=PERMY2000JAN;
PLOT SALE*DAY;
RUN;
96
text
97
Module 2 Summary
100
2-31
2-32
Session 1 Summary
101
Module 3
3.1
3.2
3-2
Macro Functions
Macro functions
have similar syntax as corresponding DATA step
character functions
yield similar results
manipulate macro variables and expressions
represent macro triggers
are executed by the macro processor.
Macro Functions
Selected character string manipulation functions:
%UPCASE
%SUBSTR
%SCAN
%INDEX
%LENGTH
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
540
541
542
543
544
545
%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;
11
3-3
3-4
Case Sensitivity
Partial Log
539
540
541
542
543
544
545
%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;
where paid="n";
13
14
15
Artificial Intelligence
24
9600
Basic Telecommunications
14
11130
13
20800
Database Design
17
6375
19
12350
16
continued...
17
3-5
3-6
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
Quick Quiz
Question: Use todays 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;
Submit your answer as a text message.
20
macro triggers
text
"01%substr(&sysdate9,3)"d
&sysdate9 resolves:
%substr(30OCT2004,3)
%substr executes:
OCT2004
final substitution:
"01OCT2004"d
21
22
3-7
3-8
23
24
25
%let libref=%scan(work.current,1);
%scan
executes:
%let libref=work;
26
3-9
3-10
WORK.CURRENT
DATA
V9
Thu, Feb 05, 2004 02:04:21 PM
Thu, Feb 05, 2004 02:04:21 PM
Observations
Variables
Indexes
Observation Length
Deleted Observations
Compressed
Sorted
0
5
0
56
0
NO
NO
WINDOWS_32
wlatin1 Western (Windows)
Engine/Host Dependent Information
27
Release Created
Host Created
8192
1
1
145
0
0
C:\temp\SAS Temporary
Files\_TD2140\CURRENT.sas7bdat
9.0101M0
WIN_PRO
31
3-11
3-12
33
* /
NOT
, <
>
LE
GE
= ;
NE
34
The %BQUOTE function is one of several macro quoting functions designed for specialized purposes.
35
36
Quick Quiz
Given the following code:
%let name=Valdez,Sanita;
%let lname=%scan(&name,1);
37
38
3-13
3-14
%let lname=%scan(Valdez,Sanita,1);
The comma from the resolved value of &name is used as
an argument separator for the %SCAN function. The
second argument in the %SCAN function is the text
Sanita.
The %SCAN function expects the second argument to be
a number, therefore you get the following error message:
ERROR: Argument 2 to macro function %SCAN is not a
number.
39
%let name=Valdez,Sanita;
%let lname=%scan(%bquote(&name),1);
%put &lname;
1
40
41
44
Obs
45
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Course_
Number
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Course_
Code
C001
C002
C003
C004
C005
C006
C001
C002
C003
C004
C005
C006
C001
C002
Location
Seattle
Dallas
Boston
Seattle
Dallas
Boston
Dallas
Boston
Seattle
Dallas
Boston
Seattle
Boston
Seattle
Begin_
Date
26OCT2004
07DEC2004
11JAN2005
25JAN2005
01MAR2005
05APR2005
24MAY2005
14JUN2005
19JUL2005
16AUG2005
20SEP2005
04OCT2005
15NOV2005
06DEC2005
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Hallis, Dr. George
Berthan, Ms. Judy
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Tally, Ms. Julia
Berthan, Ms. Judy
Hallis, Dr. George
Wickam, Dr. Alice
3-15
3-16
46
47
48
%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
Obs
1
2
50
1
2
Course_
Code
C001
C002
Location
Seattle
Dallas
Begin_
Date
26OCT2004
07DEC2004
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
3-17
3-18
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.
Refer to Exercise 2 for Module 3 in Appendix A.
Module 3 Summary
54
4.2
4-2
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-name follows SAS naming conventions.
macro-text can include
any text
SAS statements or steps
macro variables, functions, statements, or calls
any combination of the above.
4
Macro Compilation
When a macro definition is submitted,
macro language statements are
checked for syntax errors
compiled
SAS statements and other text are not
checked for syntax errors
compiled
the macro is stored as an entry in a SAS catalog, the
temporary catalog work.sasmacr by default.
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.
General form of the MCOMPILENOTE= option:
OPTIONS
OPTIONSMCOMPILENOTE=ALL
MCOMPILENOTE=ALL||NONE;
NONE;
The default setting is MCOMPILENOTE=NONE.
The MCOMPILENOTE= option is new in SAS9.
4-3
4-4
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.
proc catalog cat=work.sasmacr;
contents;
title "My Temporary Macros";
quit;
PROC CATALOG Output
My Temporary Macros
Contents of Catalog WORK.SASMACR
# Name Type
Create Date
Modified Date Description
---------------------------------------------------------------1 TIME MACRO 11JUN2004:15:55:59 11JUN2004:15:55:59
8
Calling a Macro
A macro call
causes the macro to execute
is specified by placing a percent sign before the name
of the macro
can be made anywhere in a program (similar to a
macro variable reference)
represents a macro trigger
is not a statement (no semicolon required).
General form of a macro call:
%macro-name
%macro-name
9
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
Message generated from the execution of %TIME.
The current time is 15:55:59.05.
10
4-5
4-6
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.
Example: Write a macro that generates a PROC PRINT
step. Reference macro variables within the macro.
%macro printdsn;
proc print data=&dsn;
var &vars;
run;
%mend;
macro2
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.
Compiler
Symbol Table
Word Scanner
Macro Processor
Input Stack
work.sasmacr
%let
%let dsn=perm.courses;
dsn=perm.courses;
%let
%let vars=days
vars=days fee;
fee;
%printdsn
%printdsn
##
11
22
Name
Name
PRINTDSN
PRINTDSN
TIME
TIME
Type
Type
MACRO
MACRO
MACRO
MACRO
17
Program Flow
The macro processor executes the %LET statements and
populates the symbol table.
Compiler
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Word Scanner
Macro Processor
Input Stack
work.sasmacr
%printdsn
%printdsn
##
11
22
18
Name
Name
PRINTDSN
PRINTDSN
TIME
TIME
Type
Type
MACRO
MACRO
MACRO
MACRO
4-7
4-8
Program Flow
When the macro processor receives %PRINTDSN, it locates
PRINTDSN.MACRO within the work.sasmacr catalog.
Compiler
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Word Scanner
Macro Processor
%printdsn
%printdsn
Input Stack
work.sasmacr
##
11
22
Name
Name
PRINTDSN
PRINTDSN
TIME
TIME
Type
Type
MACRO
MACRO
MACRO
MACRO
19
Program Flow
The macro processor opens PRINTDSN.MACRO. There
are no macro language statements to execute.
Compiler
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Word Scanner
Macro Processor
Input Stack
PRINTDSN.MACRO
%macro
%macro printdsn;
printdsn;
proc
proc print
print data=&dsn;
data=&dsn;
var
var &vars;
&vars;
run;
run;
%mend;
%mend;
20
Program Flow
The macro processor places the macro text on the input
stack.
Compiler
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Word Scanner
Macro Processor
Input Stack
PRINTDSN.MACRO
proc
proc print
print data=&dsn;
data=&dsn;
var
var &vars;
&vars;
run;
run;
%macro
%macro printdsn;
printdsn;
proc
proc print
print data=&dsn;
data=&dsn;
var
var &vars;
&vars;
run;
run;
%mend;
%mend;
21
Program Flow
Macro activity pauses while the word scanner tokenizes
text placed on the input stack by the macro processor.
Compiler
proc
proc print
print data=
data=
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Word Scanner
Macro Processor
Input Stack
var
var &vars;
&vars;
run;
run;
PRINTDSN.MACRO
&dsn;
&dsn;
%macro
%macro printdsn;
printdsn;
proc
proc print
print data=&dsn;
data=&dsn;
var
var &vars;
&vars;
run;
run;
%mend;
%mend;
22
Program Flow
Macro variable references are passed to the macro
processor.
Compiler
proc
proc print
print data=
data=
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Word Scanner
Macro Processor
&dsn
&dsn
Input Stack
var
var &vars;
&vars;
run;
run;
PRINTDSN.MACRO
;;
%macro
%macro printdsn;
printdsn;
proc
proc print
print data=&dsn;
data=&dsn;
var
var &vars;
&vars;
run;
run;
%mend;
%mend;
23
Program Flow
Symbolic substitution is performed. Word scanning
continues.
Compiler
proc
proc print
print data=
data=
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Word Scanner
Macro Processor
Input Stack
perm.courses;
perm.courses;
var
var &vars;
&vars;
run;
run;
24
PRINTDSN.MACRO
%macro
%macro printdsn;
printdsn;
proc
proc print
print data=&dsn;
data=&dsn;
var
var &vars;
&vars;
run;
run;
%mend;
%mend;
4-9
4-10
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.
Compiler
proc
proc print
print data=perm.courses;
data=perm.courses;
var
var days
days fee;
fee;
Word Scanner
run;
run;
Input Stack
Symbol Table
DSN
perm.courses
DSN
perm.courses
VARS
days
VARS
days fee
fee
Macro Processor
PRINTDSN.MACRO
%macro
%macro printdsn;
printdsn;
proc
proc print
print data=&dsn;
data=&dsn;
var
var &vars;
&vars;
run;
run;
%mend;
%mend;
25
Macro Execution
The SAS log reflects that a PROC PRINT step executed.
Partial SAS Log
243
244
245
%let dsn=perm.courses;
%let vars=days fee;
%printdsn
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
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;
The default setting is NOMPRINT.
27
4-11
Macro Execution
Example: Set the MPRINT option before calling the
macro.
Partial SAS Log
267 options mprint;
268 %printdsn
MPRINT(PRINTDSN):
proc print data=perm.courses;
MPRINT(PRINTDSN):
var days fee;
MPRINT(PRINTDSN):
run;
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.
proc catalog cat=work.sasmacr;
contents;
title "My Temporary Macros";
quit;
PROC CATALOG Output
My Temporary Macros
Contents of Catalog WORK.SASMACR
# Name
Type
Create Date
Modified Date Description
-------------------------------------------------------------------1 PRINTDSN MACRO 15JUN2004:15:58:21 15JUN2004:15:58:21
2 TIME
MACRO 15JUN2004:15:55:59 15JUN2004:15:55:59
29
4-12
Macro Storage
Macros are stored in the work library, by default.
The MSTORED system option enables storage of compiled
macros in a permanent SAS library.
The SASMSTORE= system option designates a permanent
library to store compiled macros.
OPTIONS
OPTIONSMSTORED
MSTOREDSASMSTORE=libref
SASMSTORE=libref;;
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;
The STORE option stores the compiled macro in the library
indicated by the SASMSTORE= system option.
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;
Call the PRINTDSN macro in a new SAS session.
libname perm '.';
options mstored sasmstore=perm;
%let dsn=perm.courses;
%let vars=days fee;
%printdsn
32
macro3
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;
The SOURCE option stores the macro source code along
with the compiled code.
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;
Call the PRINTDSN macro in a new SAS session.
libname perm '.';
options mstored sasmstore=perm;
%let dsn=perm.courses;
%let vars=days fee;
%printdsn
macro4
35
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-13
4-14
Macro Storage
Example: Copy the source code from the stored
PRINTDSN macro to the SAS log.
%copy printdsn / source;
Partial SAS Log
265 %copy printdsn / source;
%macro printdsn / store source;
proc print data=&dsn;
var &vars;
run;
%mend;
37
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-15
4-16
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;
Parameter names are
parenthesized
comma-delimited.
45
4-17
Macro Parameters
General form of a macro call with parameters:
%macro-name(value-1,
%macro-name(value-1,
value-n)
value-n)
Parameter values are
parenthesized
comma-delimited.
Parameter values can be any text, null values, macro
variable references, or macro calls.
46
To assign a null value to one or more positional parameters, use commas as placeholders for the
omitted values.
47
perm.courses
days fee
Global Table
SYSDAY
Tuesday
SYSLAST _NULL_
CITY
Dallas
AMOUNT
975
4-18
48
Quick Quiz
Does a %LET statement outside of a macro program
create a macro variable in the global or local symbol
table?
Answer with your seat indicator:
Yes = Global
No = Local
49
Positional Parameters
Positional parameters use a one-to-one correspondence
between
parameter names supplied on the macro definition
parameter values supplied on the macro call.
%macro printdsn(dsn,vars);
proc print data=&dsn;
var &vars;
run;
%mend;
%printdsn(perm.courses,days fee)
51
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-19
4-20
Keyword Parameters
General form of a macro call with keyword parameters:
%macro-name(keyword=value,
%macro-name(keyword=value,,
,keyword=value)
keyword=value)
keyword=value combinations can be
specified in any order
omitted from the call without placeholders.
If omitted from the call, a keyword parameter receives
its default value. To omit every keyword parameter from
a macro call, specify %macro-name(). Specifying
%macro-name without the parentheses may not
immediately execute the macro.
55
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()
56
param2
4-21
4-22
4-23
4-24
62
4-25
4-26
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.
Refer to Exercise 2 for Module 4 in Appendix A.
Module 4 Summary
69
Session 2 Summary
70
4-27
5.2
5.3
5-2
10
11
Student_Name
Student_Company
Reston Railway
Motor Communications
Reston Railway
Von Crump Seafood
Semi;Conductor
SSS Inc.
Paralegal Assoc.
QA Information Systems Center
Reston Railway
So. Cal. Medical Center
Alforone Chemical
Reston Railway
Physicians IPA
SII
Federated Bank
Amberly Corp.
Lomax Services
Reston Railway
Sailbest Ships
Snowing Petroleum
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
Many applications require macro variables to have values based on data values, programming logic, or
expressions.
12
%let crsnum=3;
data revenue;
set perm.all end=final;
where course_number=&crsnum;
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;
proc print data=revenue;
var student_name student_company paid;
title "Paid Status for Course &crsnum";
footnote "&foot";
run;
symput1
Student_Name
Student_Company
Reston Railway
Motor Communications
Reston Railway
Von Crump Seafood
Semi;Conductor
SSS Inc.
Paralegal Assoc.
QA Information Systems Center
Reston Railway
So. Cal. Medical Center
Alforone Chemical
Reston Railway
Physicians IPA
SII
Federated Bank
Amberly Corp.
Lomax Services
Reston Railway
Sailbest Ships
Snowing Petroleum
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
13
Symbol
Table
Symbol Table
crsnum
5-3
5-4
crsnum
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:
%let crsnum=3;
%let crsnum=8;
Symbol Table
crsnum
crsnum
3
8
17
Example:
%let crsnum=3;
%let crsnum=8;
18
Symbol Table
crsnum
Symbol Table
crsnum
19
Symbol Table
crsnum
foot
3
Some Fees Due
5-5
5-6
Symbol Table
crsnum
foot
3
All Students Paid
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.
Symbol Table
crsnum
foot
3
All Students Paid
SYMPUT
character literals
No macro
triggers within
DO groups
end;
run;
symput2
5-7
5-8
26
end;
end;
run;
Fixed Macro
Variable Value
5-9
5-10
SAS Output
Paid Status for Course 3
Obs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Student_Name
Student_Company
Reston Railway
Motor Communications
Reston Railway
Von Crump Seafood
Semi;Conductor
SSS Inc.
Paralegal Assoc.
QA Information Systems Center
Reston Railway
So. Cal. Medical Center
Alforone Chemical
Reston Railway
Physicians IPA
SII
Federated Bank
Amberly Corp.
Lomax Services
Reston Railway
Sailbest Ships
Snowing Petroleum
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
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
Program Flow
The statements are tokenized.
Compiler
Word
Scanner
Input
Stack
Macro Processor
data
data
_null_
_null_
;;
call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
%let
%let foot=All
foot=All Students
Students Paid;
Paid;
run;
run;
30
Program Flow
The %LET statement is submitted.
Compiler
Word
Scanner
data
data _null_;
_null_;
call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
%%
let
let
foot
foot
==
All
All
Students
Students
Paid
Paid
;;
Macro Processor
run;
run;
Input
Stack
31
Program Flow
When a macro trigger is encountered, it is passed to the
macro processor for evaluation.
Compiler
data
data _null_;
_null_;
call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
Macro Processor
Word
Scanner
Input
Stack
32
foot
foot
==
All
All
Students
Students
Paid
Paid
;;
run;
run;
%let
%let
5-11
5-12
Program Flow
The macro processor requests tokens until a semicolon
is encountered, then executes the macro statement.
Compiler
data
data _null_;
_null_;
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
Input
Stack
33
run;
run;
Program Flow
Tokenization resumes.
Compiler
data
data _null_;
_null_;
call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
Macro Processor
Word
Scanner
run;
run;
Symbol Table
foot
Input
Stack
34
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.
Execute
data
data _null_;
_null_;
call
call symput('foot','Some
symput('foot','Some Fees
Fees Due');
Due');
run;
run;
Macro Processor
Word
Scanner
Symbol Table
foot
35
Input
Stack
Student_Company
Reston Railway
Motor Communications
Reston Railway
Von Crump Seafood
Semi;Conductor
SSS Inc.
Paralegal Assoc.
QA Information Systems Center
Reston Railway
So. Cal. Medical Center
Alforone Chemical
Reston Railway
Physicians IPA
SII
Federated Bank
Amberly Corp.
Lomax Services
Reston Railway
Sailbest Ships
Snowing Petroleum
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
36
37
38
5-13
5-14
call symput('numpaid',paidup);
call symput('numstu',total);
call symput('crsname',course_title);
end;
run;
proc print data=revenue noobs;
var student_name student_company paid;
title "Fee Status for &crsname (#&crsnum)";
footnote "Note: &numpaid out of &numstu paid";
run;
symput3
39
40
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
There are extra blanks between the course title and course number, as well as extra blanks before
14 and 20 in the footnote.
5-15
43
call symput('numpaid',trim(left(paidup)));
call symput('numstu',trim(left(total)));
call symput('crsname',trim(course_title));
end;
run;
proc print data=revenue noobs;
var student_name student_company paid;
title "Fee Status for &crsname (#&crsnum)";
footnote "Note: &numpaid out of &numstu paid";
run;
symput4
44
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
45
PAID
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
Student Activity
Open sa-symputds.sas.
Obs
1
Course_
Code
C004
Course_Title
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
Course_
Code
C004
Course_Title
Database Design
Symbol Table
first
second
48
course_title
Database Design
Student_Name
Student_Company
Reston Railway
Motor Communications
Reston Railway
Von Crump Seafood
Semi;Conductor
SSS Inc.
Paralegal Assoc.
QA Information Systems Center
Reston Railway
So. Cal. Medical Center
Alforone Chemical
Reston Railway
Physicians IPA
SII
Federated Bank
Amberly Corp.
Lomax Services
Reston Railway
Sailbest Ships
Snowing Petroleum
49
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
5-17
5-18
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)
source is a constant, variable, or expression (numeric or character).
format is any SAS or user-defined format.
format determines
the width of the resulting string
whether the string is right- or left-aligned.
Refer to Exercise 1 for Module 5 in Appendix A.
52
53
PAID
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
5-19
5-20
symput7
55
Student_Name
Student_Company
Reston Railway
Motor Communications
Reston Railway
Von Crump Seafood
Semi;Conductor
SSS Inc.
Paralegal Assoc.
QA Information Systems Center
Reston Railway
So. Cal. Medical Center
Alforone Chemical
Reston Railway
Physicians IPA
SII
Federated Bank
Amberly Corp.
Lomax Services
Reston Railway
Sailbest Ships
Snowing Petroleum
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
56
57
58
Obs
1
2
3
4
5
6
7
8
9
10
11
12
Course_
Code
C001
C001
C002
C002
C003
C003
C004
C004
C005
C005
C006
C006
Location
Boston
Dallas
Boston
Seattle
Boston
Seattle
Dallas
Seattle
Boston
Dallas
Boston
Seattle
ENROLLMENT PERCENT
28
18
20
33
20
30
23
27
28
25
27
20
9.3645
6.0201
6.6890
11.0368
6.6890
10.0334
7.6923
9.0301
9.3645
8.3612
9.0301
6.6890
5-21
5-22
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.
If you do not see the results with the changes, scroll
down in the GRAPH1 window.
How many students attended courses from 01Jan2005
through 31Jul2005?
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
Paid
N
Y
N
Y
Y
63
64
5-23
5-24
65
Course_
Number
1
2
3
4
5
6
7
8
9
10
Course_
Code
C001
C002
C003
C004
C005
C006
C001
C002
C003
C004
Begin_
Date
Location
Seattle
Dallas
Boston
Seattle
Dallas
Boston
Dallas
Boston
Seattle
Dallas
26OCT2004
07DEC2004
11JAN2005
25JAN2005
01MAR2005
05APR2005
24MAY2005
14JUN2005
19JUL2005
16AUG2005
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Hallis, Dr. George
Berthan, Ms. Judy
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
66
69
5-25
5-26
71
Quick Quiz
How many macro variables are created with the program
named sa-symput?
Listing of PERM.COURSES Data Set
Obs
Course_
Code
1
2
3
4
5
6
C001
C002
C003
C004
C005
C006
Course_Title
Basic Telecommunications
Structured Query Language
Local Area Networks
Database Design
Artificial Intelligence
Computer Aided Design
Days
3
4
3
2
2
5
Fee
$795
$1150
$650
$375
$400
$1600
data _null_;
set perm.courses;
call symput(course_code,trim(course_title));
run;
sa-symput
73
data
data _null_;
_null_;
set
set perm.schedule;
perm.schedule;
call
call symput('teach'||left(course_number),
symput('teach'||left(course_number),
trim(teacher));
trim(teacher));
Macro Processor
Word
Scanner
Input
Stack
run;
run;
Symbol Table
%put
%put _user_;
_user_;
SYSDAY
Tuesday
76
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
data _null_;
set perm.schedule;
call symput('teach'||
left(course_number),
trim(teacher));
run;
Partial PDV
Course_
Number
N
8
Teacher
$
20
Symbol Table
SYSDAY
Tuesday
77
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
data _null_;
set perm.schedule;
call symput('teach'||
left(course_number),
trim(teacher));
run;
Partial PDV
Course_
Number
N
8
Teacher
$
20
78
Tuesday
5-27
5-28
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Partial PDV
Course_
Number
N
8
Teacher
$
20
data _null_;
set perm.schedule;
call symput('teach'||
left(course_number),
trim(teacher));
run;
79
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Tuesday
Hallis, Dr. George
Automatic return
data _null_;
set perm.schedule;
call symput('teach'||
left(course_number),
trim(teacher));
run;
Partial PDV
Course_
Number
N
8
Teacher
$
20
80
Tuesday
Hallis, Dr. George
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
data _null_;
set perm.schedule;
call symput('teach'||
left(course_number),
trim(teacher));
run;
Partial PDV
Course_
Number
N
8
Teacher
$
20
81
SYSDAY
TEACH1
Tuesday
Hallis, Dr. George
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Partial PDV
Course_
Number
N
8
data _null_;
set perm.schedule;
call symput('teach'||
left(course_number),
trim(teacher));
run;
Teacher
$
20
82
Tuesday
Hallis, Dr. George
Wickam, Dr. Alice
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Partial PDV
Course_
Number
N
8
Teacher
$
20
data _null_;
set perm.schedule;
call symput('teach'||
left(course_number),
trim(teacher));
run;
83
Tuesday
Hallis, Dr. George
Wickam, Dr. Alice
Input
Stack
84
%%
put
put
_user_;
_user_;
Symbol Table
SYSDAY
TEACH1
TEACH2
Tuesday
Hallis, Dr. George
Wickam, Dr. Alice
5-29
5-30
%put
%put _user_;
_user_;
Symbol Table
Input
Stack
SYSDAY
TEACH1
TEACH2
85
Tuesday
Hallis, Dr. George
Wickam, Dr. Alice
%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;
87
indirect3
Student Activity
Open sa-indirect.sas.
Submit the code and review the results.
89
91
%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"; Substitute
run;
5-31
5-32
92
Paid
N
Y
N
Y
Y
93
&teach&crs
1st scan
2nd scan
(only occurs when
&& is encountered)
94
&&teach&crs
&teach&crs
&&teach&crs
&teach 3
WARNING
2nd scan
(only occurs when
&& is encountered)
95
&teach&crs
&teach 3
&&teach&crs
& teach3
WARNING
2nd scan
(only occurs when
&& is encountered)
96
&teach&crs
&teach 3
&&teach&crs
& teach3
WARNING
2nd scan
(only occurs when
&& is encountered)
97
5-33
5-34
3
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Scan sequence:
&&teach&crs
&teach3
98
Quick Quiz
Given the following symbol table, what does
&&teach&crs resolve to?
Symbol Table
Value
Variable
CRS
TEACH1
TEACH2
TEACH3
99
2
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
3
3
3
to Forest, Mr. Peter
5-35
5-36
SAS Output
Roster for Course 3
Taught by Forest, Mr. Peter
Student_Name
Bills, Ms. Paulette
Chevarley, Ms. Arlene
Clough, Ms. Patti
Crace, Mr. Ron
Davis, Mr. Bruce
Elsins, Ms. Marisa F.
Gandy, Dr. David
Gash, Ms. Hedy
Haubold, Ms. Ann
Hudock, Ms. Cathy
Kimble, Mr. John
Kochen, Mr. Dennis
Larocque, Mr. Bret
Licht, Mr. Bryan
McKnight, Ms. Maureen E.
Scannell, Ms. Robin
Seitz, Mr. Adam
Smith, Ms. Jan
Sulzbach, Mr. Bill
Williams, Mr. Gene
Paid
Y
N
N
Y
Y
N
Y
Y
Y
Y
N
Y
Y
Y
Y
N
Y
N
Y
Y
107
5-37
5-38
109
110
10
%put &crsid1, &date1;
C003, 01/10/2006
11
%put &crsid2, &date2;
C004, 01/24/2006
SAS Output
SQL result
Course
Code
Begin
C003
01/10/2006
C004
01/24/2006
C005
02/28/2006
C006
03/28/2006
5-39
5-40
C003
01/10/2006
C004
01/24/2006
C005
02/28/2006
C006
03/28/2006
113
114
115
Location
Boston
Dallas
Seattle
sql4
Module 5 Summary
119
120
Obs
Course_
Code
1
2
3
4
5
6
C001
C002
C003
C004
C005
C006
Course_Title
Basic Telecommunications
Structured Query Language
Local Area Networks
Database Design
Artificial Intelligence
Computer Aided Design
Days
3
4
3
2
2
5
Fee
$795
$1150
$650
$375
$400
$1600
5-41
5-42
122
C002
Basic Telecommunications
Structured Query Language
Local Area Networks
Database Design
Artificial Intelligence
Computer Aided Design
Scan sequence:
&&&crsid
123
&c002
&&&crsid
1st scan
& c002
2nd scan
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
&&&crsid
&C006
Computer
Aided
Design
5-43
5-44
127
5-45
5-46
6.2
6.3
6-2
Simple Loops
Many macro applications require iterative processing.
The iterative %DO statement can repeatedly
execute macro language statements
generate SAS code.
General form of the iterative %DO statement:
%DO
%DO index-variable=start
index-variable=start %TO
%TOstop
stop<%BY
<%BY increment>;
increment>;
text
text
%END;
%END;
Simple Loops
Simple Loops
Text can be
constant text
macro variables or expressions
macro statements
macro calls.
6-3
6-4
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
Obs
1
2
3
4
5
Course_
Number
Course_
Code
Location
1
2
3
4
5
C001
C002
C003
C004
C005
Seattle
Dallas
Boston
Seattle
Dallas
Begin_
Date
23OCT2000
04DEC2000
08JAN2001
22JAN2001
26FEB2001
Teacher
Hallis, Dr. George
Wickam, Dr. Alice
Forest, Mr. Peter
Tally, Ms. Julia
Hallis, Dr. George
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
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
year1999
data year&year;
raw1999.dat
infile "raw&year..dat";
input course_code $4.
location
$15.
begin_date date9.
teacher
$25.;
run;
proc print data=year&year;
year1999
title "Scheduled classes for &year";
run;
%end;
%mend readraw;
%readraw(first=2000,last=2002)
11
1999
loop2
%DO loop index variable YEAR is now 2001; loop will iterate again.
data year2001;
infile "raw2001.dat";
input course_code $4. location $15. begin_date date9. teacher $25.;
run;
NOTE: There were 12 observations read from the data set WORK.YEAR2001.
MLOGIC(READRAW):
MPRINT(READRAW):
MPRINT(READRAW):
MPRINT(READRAW):
MPRINT(READRAW):
13
%DO loop index variable YEAR is now 2002; loop will iterate again.
data year2002;
infile "raw2002.dat";
input course_code $4. location $15. begin_date date9. teacher $25.;
run;
6-5
6-6
14
libname
PERM
PERM
PERM
PERM
PERM
memname
ALL
COURSES
REGISTER
SCHEDULE
STUDENTS
memtype
DATA
DATA
DATA
DATA
DATA
%put _user_;
DSN1 ALL
DSN2 COURSES
DSN3 REGISTER
DSN4 SCHEDULE
DSN5 STUDENTS
TOTALDSN 5
15
loop3
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
&lib..&&dsn&i
PERM.&dsn4
PERM.SCHEDULE
18
6-7
6-8
Course_
Number
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Course_
Code
C001
C002
C003
C004
C005
C006
C001
C002
C003
C004
C005
C006
C001
C002
C003
C004
C005
C006
Location
Seattle
Dallas
Boston
Seattle
Dallas
Boston
Dallas
Boston
Seattle
Dallas
Boston
Seattle
Boston
Seattle
Dallas
Boston
Seattle
Dallas
Begin_
Date
Teacher
26OCT2004
07DEC2004
11JAN2005
25JAN2005
01MAR2005
05APR2005
24MAY2005
14JUN2005
19JUL2005
16AUG2005
20SEP2005
04OCT2005
15NOV2005
06DEC2005
10JAN2006
24JAN2006
28FEB2006
28MAR2006
21
continued...
22
DATA perm.schedule
I
COUNT 3
VAR location
SITE3 Seattle
SITE2 Dallas
SITE1 Boston
23
otherwise;
end;
run;
%mend sites;
%sites(data=perm.schedule, var=location)
24
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-9
6-10
27
33
34
35
6-11
6-12
36
37
49
Always Print
the
Daily Report
Is it
Friday?
50
Yes
6-13
6-14
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;
expression
Conditional Processing
The text following keywords %THEN and %ELSE can be
a macro programming statement
constant text
an expression
a macro variable reference
a macro call.
Macro language expressions are similar to DATA step
expressions, except the following, which are not valid in the
macro language:
1 <= &x <= 10
special WHERE operators.
52
CAUTION
Compound expressions can be specified using the AND and OR operators. Do not precede
these keywords with %.
55
6-15
6-16
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( )
Change your seat indicator to Yes or No.
sa-prob
59
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
62
63
6-17
6-18
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.
66
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
run;
%mend;
options mprint mlogic;
%attend(start=01jul2005)
%attend(C003)
70
cond04
6-19
6-20
Ending execution.
71
Ending execution.
72
cond05
745 %choice(OWED)
MLOGIC(CHOICE): Beginning execution.
MLOGIC(CHOICE): Parameter STATUS has value OWED
MPRINT(CHOICE):
data fees;
MPRINT(CHOICE):
set perm.all;
MLOGIC(CHOICE): %IF condition %upcase(&status)=PAID is FALSE
MPRINT(CHOICE):
where paid = 'N';
MPRINT(CHOICE):
keep student_name course_code begin_date totalfee
latechg;
MPRINT(CHOICE):
latechg=fee*1.10;
MPRINT(CHOICE):
if location='Boston' then totalfee=fee*1.06;
MPRINT(CHOICE):
else if location='Seattle' then
totalfee=fee*1.025;
MPRINT(CHOICE):
else if location='Dallas' then totalfee=fee*1.05;
MPRINT(CHOICE):
run;
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
6-21
6-22
cond06
Student Activity
Submit the program below. Will this code run without
errors?
%macro counts (cols=_all_, rows=);
proc freq data=perm.all;
tables
%if &rows ne %then &rows *;;
&cols
;
run;
%mend counts;
%counts(cols=paid, rows=course_number)
sa-partial
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)
The %INDEX function
searches argument1 for the first occurrence of
argument2
returns an integer representing the position in
argument1 of the first character of argument2 if there
is an exact match
returns 0 if there is no match.
83
6-23
6-24
Parameter Validation
%INDEX(argument1,
%INDEX(argument1,argument2)
argument2)
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)
Unmute your phone and answer verbally.
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
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
6-25
6-26
93
94
Value
23FEB04
Monday
9.1
.
.
.
value1
value2
96
97
98
6-27
6-28
99
100
Value
value1
value2
.
.
.
value1
value2
102
104
105
6-29
6-30
106
%LET MACVAR=VALUE;
Macro Processor
Yes
No
Does MACVAR already exist
in the global table?
No
Yes
&MACVAR
Macro Processor
Does MACVAR exist in the
local table?
Yes
No
Does MACVAR exist in the
global table?
No
Yes
108
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
111
%outer
%macro outer;
%local x;
%let x=1;
%inner
%mend outer;
%macro inner;
%local y;
%let y=&x;
%mend inner;
112
0
OUTER Local Table
X
6-31
6-32
Global Table
%macro outer;
%local x;
%let x=1;
%inner
%mend outer;
%macro inner;
%local y;
%let y=&x;
%mend inner;
0
OUTER Local Table
X
1
INNER Local Table
Y
113
%macro outer;
%local x;
%let x=1;
%inner
%mend outer;
%macro inner;
%local y;
%let y=&x;
%mend inner;
0
OUTER Local Table
X
1
INNER Local Table
Y
114
%macro outer;
%local x;
%let x=1;
%inner
%mend outer;
%macro inner;
%local y;
%let y=&x;
%mend inner;
115
0
OUTER Local Table
X
%macro outer;
%local x;
%let x=1;
%inner
%mend outer;
%macro inner;
%local y;
%let y=&x;
%mend inner;
116
117
118
%macro numobs(lib,dsn);
Why is NUM
%global num;
declared global in
%let num=0;
the NUMOBS
proc sql noprint;
macro? Is there
select (nobs-delobs) into :num
another solution?
from dictionary.tables
where libname="%upcase(&lib)"
and memname="%upcase(&dsn)";
quit;
%let num=#
%mend numobs;
%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..;
symbol1
%mend check;
6-33
6-34
%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
Global Table
check Local Table
comp
Reston Railway
numobs Local Table
lib
dsn
120
work
subset
num
Global Table
check Local Table
comp
121
Reston Railway
numobs Local Table
lib
dsn
work
subset
num
14
check Local Table
comp
Reston Railway
numobs Local Table
lib
dsn
122
work
subset
Student Activity
123
%macro numobs(lib,dsn);
Why is NUM
%*global num;
declared global in
%let num=0;
the NUMOBS
proc sql noprint;
macro?
select (nobs-delobs) into :num
from dictionary.tables
Submit the
where libname="%upcase(&lib)"
and memname="%upcase(&dsn)";
program
quit;
sa-symbol1.sas.
%let num=#
Notice the
%mend numobs;
%global num;
%macro check(comp);
statement is now
data subset;
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..;
sa-symbol1
%mend check;
125
%macro numobs(lib,dsn);
Omit the * from
%global num;
the %global num;
%let num=0;
statement.
proc sql noprint;
select (nobs-delobs) into :num
Submit the
from dictionary.tables
program
where libname="%upcase(&lib)"
and memname="%upcase(&dsn)";
sa-symbol1.sas
quit;
again.
%let num=#
%mend numobs;
What happens?
%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..;
symbol1
%mend check;
Student Activity
6-35
6-36
%macro check(comp);
data subset;
set perm.students;
NUMOBS has finished
where student_company="&comp";
run;
execution. Therefore, its
%numobs(work,subset)
local symbol table is
%if &num>0 %then %do;
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
num
14
check Local Table
comp
Reston Railway
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)
program.
%if 14>0 %then %do;
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
comp
Reston Railway
127
%check(Reston Railway)
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: PROCEDURE SQL 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
%check(Raston Railway)
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
NOTE: PROCEDURE SQL used (Total process time):
real time
0.00 seconds
cpu time
0.00 seconds
No students from Raston Railway.
129
Module 6 Summary
132
6-37
A-2
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
TABLE2
JOINVAR
FREQVAR
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)
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
Begin
24MAY2005
01MAR2005
28MAR2006
Location
Dallas
Dallas
Dallas
Instructor
Hallis, Dr. George
Hallis, Dr. George
Berthan, Ms. Judy
A-6
2.
3.
Bill Babbitt is the only student whose name contains the text string Babbit.
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;
Courses Taken by Selected Students
Those with Babbit in Their Name
- Student Name=Babbitt, Mr. Bill Company=National Credit Corp. Description
Begin Location
Dallas
Dallas
Dallas
Instructor
Hallis, Dr. George
Hallis, Dr. George
Berthan, Ms. Judy
0 Session 1
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
- Student Name=Babbitt, Mr. Bill Company=National Credit Corp. Description
Basic Telecommunications
Artificial Intelligence
Computer Aided Design
Begin Location
24MAY2005 Dallas
01MAR2005 Dallas
28MAR2006 Dallas
Instructor
Hallis, Dr. George
Hallis, Dr. George
Berthan, Ms. Judy
Begin Location
Instructor
Wickam, Dr. Alice
Begin Location
24MAY2005 Dallas
25JAN2005 Seattle
28MAR2006 Dallas
Instructor
Hallis, Dr. George
Tally, Ms. Julia
Berthan, Ms. Judy
Begin Location
Instructor
Wickam, Dr. Alice
Berthan, Ms. Judy
A-7
A-8
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
4.
opt=;
lib=perm;
ds=_all_;
contents data=&lib..&ds &opt;
0 Session 1
A-9
Boston
150
Dallas
133
Seattle
151
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
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.
2.
Select File Save As from your pull-down menu. Type the name of the program,
AfterClass1 in the File Name field.
Use the %SYMDEL statement to remove the FREQVAR and JOINVAR macro variables from
the global symbol table.
%symdel freqvar joinvar;
b.
Display a list of all the user-defined macro variables that are currently in the global symbol table.
%put _user_;
1) Do you see the macro variables you deleted in this list? No
2) Do you think it is possible to delete all of the user-defined macro variables from the global
symbol table? Yes, it is. An example is given later in the course.
0 Session 2
A-11
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:
proc sort data=perm.schedule out=work.sorted;
by course_number begin_date;
run;
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
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.
2.
Table1
students
Joinvar
student_name
Freqvar
city_state
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
Submit the program sortsched shown below to create the work.sorted data set:
proc sort data=perm.schedule out=work.sorted;
by course_number begin_date;
run;
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
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
finit=S;
minit=%bquote( );
linit=F;
&finit&minit&linit;
0 Session 2
A-17
%macro printnum;
proc print data=perm.all label noobs n;
where course_number=#
var student_name student_company;
title "Enrollment for Course &num";
run;
%mend printnum;
%let num=8;
%printnum
A-18
Partial Output
Student Name
Snowing Petroleum
Southern Gas Co.
United Shoes Co.
Motor Communications
California Dept. of Insurance
Von Crump Seafood
Admiral Research & Development Co.
Imperial Steel
Basic Home Services
Crossbow of California
K&P Products
Emulate Research
Dept. of Defense
K&P Products
Silver, Sachs & Co.
Roam Publishers
Pacific Solid State Corp.
Southern Edison Co.
Sailbest Ships
Federal Landmarks
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
A-20
Partial Output
Enrollment for Course 8
Student Name
Company
Snowing Petroleum
Southern Gas Co.
United Shoes Co.
Motor Communications
California Dept. of Insurance
Von Crump Seafood
Admiral Research & Development Co.
Imperial Steel
Basic Home Services
Crossbow of California
K&P Products
Emulate Research
Dept. of Defense
K&P Products
Silver, Sachs & Co.
Roam Publishers
Pacific Solid State Corp.
Southern Edison Co.
Sailbest Ships
Federal Landmarks
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
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.
title;
%macro freq_report(table1=schedule,table2=register,
joinvar=course_number,freqvar=location);
proc sql;
select &freqvar,n(&freqvar) label='Count'
from perm.&table1,perm.&table2
where &table1..&joinvar=&table2..&joinvar
group by &freqvar;
quit;
%mend freq_report;
A-22
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.
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);
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;
%put The value of PATTERN is &pattern;
0 Session 3
A-23
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
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
The INPUT function is needed to convert character values of macro variables retrieved
by the SYMGET function into numeric SAS data values.
A-26
Name
Type
Length
Value
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.
0 Session 3
A-27
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;
Roster for Course Offered on 01/10/2006
Course_
Number
Student_Name
Chavez, Ms. Louise
Edwards, Ms. Kathy
Garza, Ms. Cheryl
Gemelos, Mr. Jerry
Green, Mr. Pat
Hipps, Mr. Rich
Kiraly, Mr. Bill
Knight, Ms. Susan
Leon, Mr. Quinton
Lewanwowski, Mr. Dale R.
McCoy, Mr. Phil
Mikles, Ms. Wendy
Morgan, Ms. Kathy
Norton, Ms. Suzanne M.
Ray, Ms. Mary Frances
Right, Ms. Tina
Schier, Ms. Joan
Smith, Mr. Anthony
Smith, Ms. Donna
Stebel, Mr. Thomas C.
Voboril, Mr. Jim
Wallace, Mr. Jules
Williams, Mr. Gregory
Ziegler, Mr. David
N = 24
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
Paid
Y
Y
Y
Y
N
N
Y
Y
N
Y
Y
N
N
Y
Y
N
Y
Y
Y
Y
Y
Y
N
N
A-28
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;
title "Roster for Course offered on &date";
proc print data=perm.register noobs n;
where course_number=15;
run;
Partial Output
Roster for Course Offered on January 10, 2006
Student_Name
Chavez, Ms. Louise
Edwards, Ms. Kathy
Garza, Ms. Cheryl
Gemelos, Mr. Jerry
Green, Mr. Pat
Course_
Number
15
15
15
15
15
Paid
Y
Y
Y
Y
N
0 Session 3
A-29
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 SAS Log
161 options symbolgen;
162 %let crs=4;
163 proc print data=perm.all noobs n;
164
where course_number=&crs;
SYMBOLGEN: Macro variable CRS resolves to
165
var student_name student_company;
SYMBOLGEN: Macro variable CRS resolves to
166
title1 "Roster for Course &crs";
SYMBOLGEN: && resolves to &.
SYMBOLGEN: Macro variable CRS resolves to
SYMBOLGEN: Macro variable START4 resolves
167
title2 "Beginning on &&start&crs";
168 run;
4
4
4
to 01/25/2005
A-30
Partial Output
Roster for Course 4
Beginning on 1/25/2005
Student_Name
Student_Company
Reston Railway
United Shoes Co.
California Lawyers Assn.
Motor Communications
Bostic Amplifier Inc.
Von Crump Seafood
Gorman Tire Corp.
Admiral Research & Development Co.
San Juan Gas and Electric
Crossbow of California
Crossbow of California
Rocks International
Alforone Chemical
Emulate Research
Bonstell Electronics
California Dept. of Insurance
Applied Technologies
SMASH Hardware Inc.
0 Session 3
Partial Output
Roster for Course 4 Beginning on 01/25/2005
Student_Name
Student_Company
Reston Railway
United Shoes Co.
California Lawyers Assn.
Motor Communications
Bostic Amplifier Inc.
Von Crump Seafood
Gorman Tire Corp.
Admiral Research & Development Co.
San Juan Gas and Electric
Crossbow of California
Crossbow of California
Rocks International
Alforone Chemical
Emulate Research
Bonstell Electronics
California Dept. of Insurance
Applied Technologies
SMASH Hardware Inc.
Candide Corporation
US Treasury
Donnelly Corp.
Sailbest Ships
Reston Railway
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-31
A-32
The SORT procedure can produce a list of distinct values for a given variable. These values can
be placed into a series of macro variables. Using a macro loop, the series of macro variables can
be processed to produce one report for each original data value. The type of variable parameter
controls whether quotes are placed around the data in the WHERE statement.
%macro printall (dsn,var);
%let dsn=%upcase(&dsn);
%let var=%upcase(&var);
proc sort data=&dsn(keep=&var) out=unique nodupkey;
by &var;
run;
data _null_;
set unique end=final;
call symputx('value'||left(_n_),&var);
if final then call symputx('count',_n_);
run;
%do i=1 %to &count;
proc print data=&dsn noobs;
where &var="&&value&i";
title "Listing of &dsn Data Set";
title2 "for &var=&&value&i";
run;
%end;
%mend;
0 Session 3
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
MPRINT(PRINTALL):
proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL):
where COURSE_CODE="C003";
MPRINT(PRINTALL):
title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL):
title2 "for COURSE_CODE=C003";
MPRINT(PRINTALL):
run;
NOTE: There were 3 observations read from the data set PERM.SCHEDULE.
WHERE COURSE_CODE='C003';
NOTE: PROCEDURE PRINT used (Total process time):
real time
0.00 seconds
cpu time
0.01 seconds
MPRINT(PRINTALL):
proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL):
where COURSE_CODE="C004";
MPRINT(PRINTALL):
title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL):
title2 "for COURSE_CODE=C004";
MPRINT(PRINTALL):
run;
NOTE: There were 3 observations read from the data set PERM.SCHEDULE.
WHERE COURSE_CODE='C004';
NOTE: PROCEDURE PRINT used (Total process time):
real time
0.00 seconds
cpu time
0.00 seconds
MPRINT(PRINTALL):
MPRINT(PRINTALL):
MPRINT(PRINTALL):
MPRINT(PRINTALL):
MPRINT(PRINTALL):
A-33
A-34
MPRINT(PRINTALL):
proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL):
where COURSE_CODE="C006";
MPRINT(PRINTALL):
title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL):
title2 "for COURSE_CODE=C006";
MPRINT(PRINTALL):
run;
NOTE: There were 3 observations read from the data set PERM.SCHEDULE.
WHERE COURSE_CODE='C006';
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)
Partial SAS Log
MPRINT(PRINTALL):
proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL):
where LOCATION="Boston";
MPRINT(PRINTALL):
title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL):
title2 "for LOCATION=Boston";
MPRINT(PRINTALL):
run;
NOTE: There were 6 observations read from the data set PERM.SCHEDULE.
WHERE LOCATION='Boston';
NOTE: PROCEDURE PRINT used (Total process time):
real time
0.00 seconds
cpu time
0.01 seconds
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
MPRINT(PRINTALL):
proc print data=PERM.SCHEDULE noobs;
MPRINT(PRINTALL):
where LOCATION="Seattle";
MPRINT(PRINTALL):
title "Listing of PERM.SCHEDULE Data Set";
MPRINT(PRINTALL):
title2 "for LOCATION=Seattle";
MPRINT(PRINTALL):
run;
NOTE: There were 6 observations read from the data set PERM.SCHEDULE.
WHERE LOCATION='Seattle';
NOTE: PROCEDURE PRINT used (Total process time):
0 Session 3
real time
cpu time
2.
3.
A-35
0.00 seconds
0.01 seconds
The _USER_ argument in the %PUT statement displays all user-created macro variables.
%put _user_;
Partial SAS Log
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
GLOBAL
STARTDATE17 02/28/2006
STARTDATE16 01/24/2006
DSN perm.courses
VARS days fee
STARTDATE8 06/14/2005
STARTDATE18 03/28/2006
STARTDATE9 07/19/2005
CRSNUM 3
DATE 01/11/2005
STARTDATE4 01/25/2005
STARTDATE5 03/01/2005
STARTDATE6 04/05/2005
NUMPAID 14
STARTDATE7 05/24/2005
STARTDATE11 09/20/2005
NUMSTU 20
CRSNAME Local Area Networks
DUE $3,900
STARTDATE10 08/16/2005
NUM 8
STARTDATE1 10/26/2004
STARTDATE13 11/15/2005
STARTDATE2 12/07/2004
STARTDATE12 10/04/2005
STARTDATE3 01/11/2005
STARTDATE15 01/10/2006
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
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;
proc print data=outstand;
var student_name course_number begin;
title1 "Class Dates for Students";
title2 "with Outstanding Fees";
run;
Partial SAS Output
Class Dates for Students
with Outstanding Fees
Obs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Student_Name
Amigo, Mr. Bill
Edwards, Mr. Charles
Haubold, Ms. Ann
Hodge, Ms. Rita
McGillivray, Ms. Kathy
Pancoast, Ms. Jane
Divjak, Ms. Theresa
Gandy, Dr. David
Harrell, Mr. Ken
Hill, Mr. Paul
Lewanwowski, Mr. Dale R.
Nandy, Ms. Brenda
Ng, Mr. John
Williams, Mr. Gene
Chevarley, Ms. Arlene
Course_
Number
1
1
1
1
1
1
2
2
2
2
2
2
2
2
3
begin
26OCT2004
26OCT2004
26OCT2004
26OCT2004
26OCT2004
26OCT2004
07DEC2004
07DEC2004
07DEC2004
07DEC2004
07DEC2004
07DEC2004
07DEC2004
07DEC2004
11JAN2005
0 Session 3
4.
A-37
Macro variable VAR3 does not exist until the CALL SYMPUT statement executes, so no
substitution is made.
data test:
length s1 s4 s5 $ 3;
call symput('var3','dog');
r1="cat";
r2=3;
r3="&var3";
s1=symget('var1');
s2=symget('var2');
s3=input(symget('var2'),2.);
s4=symget('var3');
s5=symget('var'||left(r2));
run;
Compilation
The attributes of each variable are determined during compilation of the resulting DATA step
program:
data test:
length s1 s4 s5 $ 3;
call symput('var3','dog');
r1="cat";
r2=3;
r3="&var3";
s1=symget('var1');
s2=symget('var2');
s3=input(symget('var2'),2.);
s4=symget('var3');
s5=symget('var'||left(r2));
run;
S1, S4, S5
R2
Lack of quotes around the assigned value indicates a numeric variable. Default length
for numeric variables is 8.
R1 & R3
Quotes around the assigned value indicate a character variable. The number of
characters inside the quotes determines the length.
S2
S3
Assignment from the INPUT function with a numeric informat indicates a numeric
variable. Default length for numeric variables is 8.
A-38
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
R3
The reference &VAR3 is a text string during execution, so this is also a hardcoded
value.
S1
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.
Name
Type
Length Value
R1
Char
cat
R2
Num
R3
Char
&var3
S1
Char
cat
S2
Char
200
S3
Num
S4
Char
dog
S5
Char
dog
0 Session 4
A-39
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.
2. Validating Macro Parameters
a. Open the paidstat program shown below into the Editor window and submit it.
%macro paid(crsnum);
proc print data=perm.register label n noobs;
var student_name paid;
where course_number=&crsnum;
title "Fee Status for Course &crsnum";
run;
%mend paid;
%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
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;
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)
Move the DATA step into a separate macro named DATEMVAR with one parameter corresponding to
the format used in the PUT function. Make DATE9. the default value of this parameter.
Place a call to the new macro before the PROC PRINT step (where the DATA step had been). Use the
value MMDDYY10. instead of the default value for the macro's parameter. Submit the revised
program.
Make certain that the reference to &TODAY in the title resolves to the formatted value of today's
date.
0 Session 4
A-41
2.
Open the program paidstat shown below into the Editor window and submit it.
%macro paid(crsnum);
proc print data=perm.register label n noobs;
var student_name paid;
where course_number=&crsnum;
title "Fee Status for Course &crsnum";
run;
%mend paid;
%paid(2)
A-42
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.
0 Session 4
d.
A-43
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
MLOGIC(PAID): %IF condition &crsnum >= 1 and &crsnum
MPRINT(PAID):
proc print data=perm.register label n
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
WHERE (course_number=2) and (paid='N');
NOTE: PROCEDURE PRINT used:
real time
2.40 seconds
cpu time
0.03 seconds
MLOGIC(PAID):
Ending execution.
is TRUE
<= 18 is TRUE
noobs;
PERM.REGISTER.
A-44
3.
B.2
B-2
Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
DATA STEP
Compiler
PROCEDURE
Parser
WORD SCANNER
GLOBAL STATEMENT
Parser
SQL
Compiler
SYMBOL TABLE
MACRO
PROCESSOR
MACRO LIBRARY
INPUT STACK
Review
create macro
variables
%LET
B-3
B-4
Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
Review
create macro
variables
retrieve macro
variables
%LET
&macvar
create macro
variables
retrieve macro
variables
%LET
&macvar
create macro
variables
retrieve macro
variables
%LET
&macvar
Review
word
scanning
time
Review
word
scanning
time
execution
time
CALL SYMPUT
word
scanning
time
execution
time
create macro
variables
retrieve macro
variables
%LET
&macvar
10
SYMGET
11
12
Question: When does SYMGET retrieve the value of the macro variable?
B-5
B-6
Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
14
15
data
data teachers;
teachers;
set
set perm.register;
perm.register;
length
length teacher
teacher $$ 20;
20;
teacher=symget(teach||left(course_number));
teacher=symget(teach||left(course_number));
Word
Scanner
run;
run;
Macro Processor
Symbol Table
Input
Stack
teach1
teach2
teach3
16
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
1
2
1
Partial PDV
Course_
Number
N
8
Paid
Teacher
$
20
Y
Y
Y
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
Initialize PDV
to missing.
.
Symbol Table
teach1
teach2
teach3
17
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
1
2
1
Partial PDV
Course_
Number
N
8
Paid
Y
Y
Y
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
Teacher
$
20
1
Symbol Table
18
teach1
teach2
teach3
B-7
B-8
Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
Paid
1
2
1
Y
Y
Y
Partial PDV
Course_
Number
N
8
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
Teacher
$
20
teacher=symget(teach1);
19
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
Paid
1
2
1
Y
Y
Y
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
Automatic output
Partial PDV
Course_
Number
N
8
Teacher
$
20
20
Automatic return
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
1
2
1
Partial PDV
Course_
Number
N
8
Teacher
$
20
Paid
Y
Y
Y
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
1
Symbol Table
21
teach1
teach2
teach3
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
Paid
1
2
1
Y
Y
Y
Partial PDV
Course_
Number
N
8
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
Teacher
$
20
2
Symbol Table
teach1
teach2
teach3
22
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
Paid
1
2
1
Y
Y
Y
Partial PDV
Course_
Number
N
8
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
Teacher
$
20
teacher=symget(teach2);
23
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
1
2
1
Partial PDV
Course_
Number
N
8
Teacher
$
20
Paid
Y
Y
Y
data teachers;
set perm.register;
length teacher $ 20;
teacher=symget(teach||
left(course_number));
run;
Symbol Table
24
teach1
teach2
teach3
B-9
B-10
Appendix B SAS Programming Flow and Macro Variable Retrieval in the DATA Step
Student_Name
Albritton, Mr. Bryan
Amigo, Mr. Bill
Chodnoff, Mr. Norman
Course_
Number
teacher
1
2
1
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