Sei sulla pagina 1di 17

INTRODUCTION TO SAS MACRO PROCESSING

James R. Bence, Ph.D.,


Co-Director of the Quantitative Fisheries Center
Professor in the Department of Fisheries and Wildlife.
Copyright by Michigan State University
March 27, 2008
Overview
These notes were prepared as materials for attendees of a Michigan State University
CSTAT Workshop. During the workshop they were background information
supporting demonstrations and hands-on SAS coding. If you were not able to attend
the workshop these notes may still provide a useful introduction to using the SAS
macro facility.
The objective of the workshop/notes is to provide a basic introduction to using the SAS
macro facility as a means to automate repetitive steps within the SAS environment,
simplify code, and extending the SAS language. This material is intended for SAS
users with no or limited prior experience with SAS macros. The intended audience is
assumed to have basic familiarity with the SAS data step and running SAS statistical
procedures. SAS macro variables are shorthand for blocks of text. SAS macros are
essentially functions that can be passed arguments. Hands-on lab exercises will provide
an opportunity write and run SAS code containing macro variables and macros. We
will cover basic concepts and illustrate examples. During the workshops this was
through both lecture and hands-on computer exercises.
Getting Help
The SAS documentation of the SAS macro facility is good and comprehensive. When
you get stuck do not hesitate to look there! To find the reference guide for macros open
up help, then SAS products->Base SAS->SAS Macro Reference.
Getting Started with SAS Macro Variables
Macro variables are just short hand names that refer to blocks of text. The easiest way
to create a macro variable is to use the %LET statement. You can use this to create the
variable and give it a value at the same time.
Here is an example:
%let db=test2;

The above line creates the macro variable db and gives this variable the value of
test2.
(Note that when you start a statement with % this tells SAS that what follows is either a
built in macro facility statement (like %let) or function, or a macro you have created
(we will return to that later). The exceptions to this are %INCLUDE, %LIST, and
%RUN which are not part of the macro facility but instead are part of base SAS. Some
macro statements and functions can be run in open code like %let. Others must be run
from within macros.)
You could put this line near the top of a SAS program if you are using the same SAS
code but wish to run it on different data sets. Instead of doing search and replaces on
the data set name, you just change the value of the macro variable, and use the macro
variable in your code.
So that leads to the question how do you refer to a macro variable?
You refer to it by preceding the variable name with & (an ampersand), as in the
following statement:
proc print data=&db;

This statement will print the contents of the data set with a name equal to the value of
the macro variable. E.g., it would print a data set named test2 if we had assignd db
the value test2.
So let us actually work our way through such a very simple example. First create two
temporary SAS data sets. Start up SAS and create two different temporary data sets:
data test1;
input a b;
cards;
1 2
4 5
;
data test2;
input a b;
cards;
3 4
4 1

;
These exceedingly simple, even silly, example data sets each have two variables (a and
b) and two observations with values for variable. Create these data sets by submitting
your program.
Now enter the following simple code:
%let db=test2;

proc print data=&db;


run;
proc plot data=&db;
plot a*b;
run;

Now just change test2 to test1 in the %let statement and rerun the code. You now
should get a print out and plot for test1 instead of test2. Obviously in this example
using a macro variable did not save much work, but imagine a hundred lines of code
with many references to the data set. With the macro you only need to make one
change and you can run your code on a different version of the data set.
More on Macro Variables and Turning Blocks of SAS Code into Macro Variable
Values
Macro variables names are subject to usual naming conventions that apply for SAS data
set variables, but the names are not subject to the same length limits as SAS data set
variables (SAS dataset variable names must be eight characters or less). More
specifically, macro variable names must start with a letter or an underscore and can be
followed by letters or digits. You can assign any name to a macro variable as long as
the name is not a reserved word. The prefixes AF, DMS, SQL, and SYS are not
recommended because they are frequently used in SAS software for automatic macro
variables.
The values assigned to SAS macro variables are considered to just be a long sequence
of characters. I.e., text not numbers. The values can be quite long strings of characters
up to 65,534 characters.
A limitation is that if the value contains certain special characters (e.g., semicolons,
quotation marks, ampersands, and percent signs) or mnemonics (e.g., AND, OR, or
LT), you must use a macro quoting function to mask the special characters.
Otherwise, the special character or mnemonic might be misinterpreted by the macro
processor. A common example where you might want to do this is when you want the
value of a macro variable to be a block of SAS code containing several SAS statements
ending in semicolons. To handle this situation you can use the str function. Without
the str function SAS would interpret the first semicolon it came to as the end of %let
statement.
For example you could assign a value to the macro variable sascode as follows
%let sascode=%str(
proc plot data=&db;
title "plot for &db";
plot a*b;
run;

);

And then just put the line


&sascode

In your program to run the block of code.


Note that in the above example another macro variables (db) was used as part of the
argument to the %str function and it was resolved to its value. This happens when the
value is assigned NOT when &sascode occurs. So if the value of db were changed
after the value of sascode was assigned but before the &sascode line this would have
no effect.
In the above example the line feeds between the SAS statements are there just to make
the code more readable (as is true for SAS code outside of a %str function too).
If you wanted the & symbol to be part of the value of the macro variable you would
need to use a different quoting function than the str function. This can get quite
complex and when you need to deal with special cases you should read about quoting
functions in the SAS macro system documentation.
Your First SAS Macro
While it is easy to assign blocks of SAS statements as the value of a macro variable,
these blocks become constants. Sometimes you want to repeat the same set of SAS
statements, but change just one or a few things. Perhaps you wish to change which
version of the data set you use, or perhaps you wish to change the dependent variable
you are analyzing. In such situations it makes more sense to define a SAS macro to
execute the SAS statements. So lets again consider the simple example of printing a
SAS data set and plotting two variables versus one another. We could define the
following SAS macro by enclosing the same block of statements we had been using by
a %macro and %mend statement:
%macro testm;
/* this is a test macro */
%* including comments is good, and this is the other form;
proc print data=&db;
run;
proc plot data=&db;
plot a*b;
run;
%mend;

This code defines a macro called testm. Once we execute this code within the
session, SAS now knows about this macro. So if we want to run the macro we would
then need two lines, one to define/assign a value to db and the second to run testm:

%let db=test1;
%testm;

Note that the semicolon at the end of your macro invocation is not required.
A SAS Macro with an Argument
The above example is a bit cumbersome in that we need two lines of code each time we
execute testm for a different database, and because the value of db is changed
globally, not just for the function testm. A better way is to define the macro testm so it
takes an argument:
/* This macro takes one argument */
%macro testm(dbin);
proc print data=&dbin;
title "print out of data set &dbin";
run;
proc plot data=&dbin;
title "plot for data set &dbin";
plot a*b;
run;
%mend;

What this change does is create a macro variable dbin that is local, so it only exists
when the macro testm is running. We then call the macro with a line like:
%testm(test1);

SAS knows to assign the argument (value within parentheses) to the local macro
variable dbin, and this gets resolved to its actual value as the macro runs. We could
then just change test1 to test2 in the above line and get new results and not leave
any side effects like changing the value of a global macro variable. In general macro
variables created in open code are global in scope and those created within macros are
local in scope to that macro, so that once the macro is done they no longer exist. We
will talk more about scope of SAS macro variables later.
Let us get a bit fancier and include multiple arguments:
/* macro taking multiple arguments */
%macro testm(dbin, depvar, indvar);
proc print data=&dbin;
title "print out of &dbin";
/* use double quotes if you want macro variable resolved */
run;
proc plot data=&dbin;
title "plot of &depvar versus &indvar for dataset &dbin";
plot &depvar*&indvar;
run;
%mend;

%testm(test1,a,b);

In this example we just list multiple local macro variables separated by commas in the
header line of the macro definition. This style uses positional definition. When we
invoke the macro we need to provide the arguments in this same order so it knows
which value to assign to which local macro variable.
Note the use of some title statements to help us keep track on our output what dataset is
being printed or plotted. Note that we use double quotes. If you use single quotes the
macro variables dont get resolved.
Macros Defined using Keywords
Up to now we have been defining macros with positional arguments. Sometimes you
might tend to use default values for most arguments and just want to change one (or a
few out of many). In such cases its better to use keyword arguments and set defaults;
/* macro taking multiple arguments via keywords*/
%macro testm(dbin=test1, depvar=a, indvar=b);
proc print data=&dbin;
title "print out of &dbin";
/* use double quotes if you want macro variable resolved */
run;
proc plot data=&dbin;
title "plot of &depvar versus &indvar for dataset &dbin";
plot &depvar*&indvar;
run;
%mend;
* use defaults;
%testm;
* use test2 and default variables;
%testm(dbin=test2);
*use test2 and b as dep varible;
%testm(dbin=test2, depvar=b, indvar=a);
*does same as above;
%testm(depvar=b,indvar=a,dbin=test2);
*uses default data and b as dep variable;
%testm(depvar=b,indvar=a);

Macros with a Variable Number of Arguments and your First Loop


What if you want to do the same thing a whole bunch of times but you dont know how
many times when you write the macro? You can use the parmbuff option in this
case. Here is an example:
/* macro with unspecified arguments */
%macro printdbs/parmbuff;
%let dbcnt=1;
%let currdb=%scan(&syspbuff,&dbcnt);
%do %while(&currdb ne);
proc print data=&currdb;

title "print out of data set &currdb";


run;
proc plot data=&currdb;
title "plot of data set &currdb";
plot a*b;
run;
%let dbcnt=%eval(&dbcnt+1);
%let currdb=%scan(&syspbuff,&dbcnt);
%end;
%mend printdbs;
%printdbs(test1,test2);

What happens here is that when the macro is invoked the parmbuff option tells SAS to
assign to the macro variable syspbuff a string equal to the text inside the parentheses.
%SCAN is a built in macro function where the first argument is a string, the second is
which item within the string to grab. There is a third argument to specify the
delimiter if your text is not separated into components by a legal delimiter for your
system (e.g., here by a comma).
%do, %while, and %end are built in macro statements that define a do loop that
executes until the while condition is false. In this case it continues to execute until the
value of currdb is null. The way this works is that dbcnt is set to 1, the first time
through the loop the value of currdb is set to the first argument (first block of text
before the first comma of syspbuff), then the proc print and proc plot statements get
executed using that value of currdb. Then dbcnt is incremented by 1 and the next value
from syspbuff is read. The loop continues until scan is told to read past the last element
syspbuff. This returns a null value and the loop is terminated.
Notice in the above code the use of the macro function %eval statement. This is
required because macro variables are just strings. If you replaced %eval(&dbcnt+1)
by just &dbcnt+1, The value of dbcnt at the end of the first time through the loop
would be the string 1+1 not the string 2. Note that %eval uses integer arithmetic.
If you need floating point arithmetic use %sysevalf .
More Things to Know about Building Macro Variables
It is often useful to combine text and the value of a macro variable, or the value of
several macro variables to obtain a single value for a new macro variable. Here are
some useful things to know.
1. Leading and trailing blanks are not included so
%let street=Maple ;
%let street= Maple;
%let street= Maple ;

are all equivalent.


2. Imbedded blanks are kept, so
%let street=Ma ple;
has blanks in the middle!
3. Unless told to do otherwise macro variables and macros on the right hand side of
macro definitions are resolved. If you actually want to create a macro variable with a
% or & as part of its value you have to use a quoting function.
4. The way macros and macro variables are resolved can lead to odd and frustrating
errors when trying to combine macro variables until you get the hang of things. Say
you you want to create a macro variable that concatenates the value of prefix and 3.
E.g., prefix might have a value of varname and you want to get a new value of
varname3. If you execute the following lines:
%let prefix=varname;
%let combname=&prefix3;
You will get an error because SAS will see the text prefix3 to the right of the & and
prefix3 is a legal SAS name for a macro variable but it does not exist. What you really
want to do here is resolve the macro prefix and then concatenate 3 to this value and
assign this result to combname. You can force resolution of the first macro variable
and then concatenation with a period. So the following would work
%let prefix=varname;
%let combname=&prefix.3;
Sometimes you might want to actually have a period concatenated to a macro variable.
In such a case you need to use two periods since the first one just gets interpreted as
requesting resolution of the first macro variable. For example the following:
%let extent=xls;
%let topic=macroclass;
%let fname=&topic..&extent;
Would produce a value for fname of macroclass.xls . The obvious application here is
when you want the macro value to be the name of a file.
SAS also resolves a macro reference when it encounters a blank, but the blank is kept in
the result. Thus
%let num=1474;
%let street=Hatch;

%let address=&num &street Road;


Would produce a value for address of 1474 Hatch Road.
Scope of Macro Variables
Macro variables are either Global or Local in scope. If you create a macro variable in
open code (i.e., not inside a macro) it will generally be Global in scope. This means
you can use it anywhere while SAS continues to run. If you create a macro variable
within a macro it will generally be Local during the execution of that macro. One
macro can call another, and the scope operates in a hierarchical fashion. For example,
consider the following code;
/* Make an example data set */
Data test3;
Input sex a b;
Cards;
1 4 5
1 3 7
1 3 4
0 3 3
0 5 9
0 6 8.5
;
Run;
%*first create a global macro variable;
%let aglobal=I am global;
%macro subset(indat,outdat,subvar);
%*subset is macro that uses subsetting if and prints results;
data &outdat;
set &indat;
if &subvar=1;
run;
%* we include call to macro printit even though not defined yet;
%printit(&outdat,&subvar of 1);
%put In the subset macro;
%put aglobal=&aglobal; /*print global macro variable to log */
%put indat=&indat; /*print macro var local to subset macro to log */
%put labtext=&labtext; /*print macro var local to printit to log */
%mend;
%macro printit(prindat,labtext);
%* printit prints specified data set and includes labtext in title;
proc print data=&prindat;
title "Results for &labtext";
run;
%put In the printit macro;
%put aglobal=&aglobal; /*print global macro variable to log */
%put indat=&indat;/*print macro var local to subset macro to log */
%put labtext=&labtext; /*print macro var local to printit to log */
%mend;
%subset(test3,test4,sex);

%put
%put
%put
%put

In open code;
aglobal=&aglobal; /*print global macro variable to log */
indat=&indat;
/*print macro var local to subset to log */
labtext=&labtext; /*print macro var local to printit to log */

In the code above the following occurs. (1) A made-up dataset is created. 1 is meant to
designate data for males versus 0 for femailes. (2) A global macro is created. It is not
really used for anything except to demonstrate its global scope. (2) Then the macro
subset is defined. It grabs a specified data set and keeps only the observations with
the specified variable equal to 1. This macro then calls the macro printit, Note that a
SAS stores defines macros and their scope in symbol tables. There may be times when
you are developing macros that it would be useful to write all or part of the contents of
the global and local symbol tables to the SAS log. To do so, use the %PUT statement
with one of the following options:
_ALL_ to get all currently defined macro variables, regardless of scope. This includes
user-defined and automatic macro variables.
_AUTOMATIC_ to get all automatic macro variables. The scope is listed as
AUTOMATIC. All automatic macro variables are global except SYSPBUFF.
_GLOBAL_ to get all user-defined global macro variables. The scope is listed as
GLOBAL. Automatic macro variables are not listed.
_LOCAL_ describes user-defined local macro variables defined within the currently
executing macro. The scope is listed as the name of the macro in which the macro
variable is defined.
_USER_ describes all user-defined macro variables, regardless of scope. The scope is
either GLOBAL, for global macro variables, or the name of the macro in which the
macro variable is defined.
course it better exist when the macro is actually run!
Next the macro printit is defined; Finally the macro subset is run; and after
printit completes subset uses %put statements to write the values of macro
variables to the SAS log.
Note that %put statements are used to write the values of macro variables to the SAS
log from within each of the two macros and in open code. The point here is that the
global macro is defined at all times after it is created. The macro variables created
within subset are defined while subset is running and this includes while macros
called from within subset are running. However the macro variables created within
printit are not defined when printit is not running.

10

Note that the %put statement is one quick way to check that the values of macro
variables are what you think they are.
Sometimes it is useful to explicitly force a macro variable to be either global or local.
Use %local or %global to do this. Inside of macro you might want to create a variable
known outside the macro so it needs to be global. Inside a macro you might be creating
and using a variable you will only use inside the macro and you are not sure if there is
macro with same name at higher level. If you specify it is local you will use that
version within the macro and not change the value of higher level versions.
Some Tricks on Debugging Macro Code
Perhaps the most important thing to remember is not specific to writing SAS macros
but applies to any computer programming. Do things in small steps or modules and
then when the pieces work put things together. For example, I usually write the SAS
code for a single analysis to check it works before attempting to automate repeated
analyses using a macro. Then my first version of the macro I set up as just the header
and perhaps some preliminary processing of the arguments, to make sure it is getting
the information in the way it is supposed to. Then I might actually put the SAS
statements inside the macro without change and make sure it runs. Finally I would
replace appropriate text in the SAS statements by the macro variables created from the
macro arguments, and see if I could get this to produce the same results.
Second it is worth checking for common errors. The SAS macro reference (help)
suggests checking for the following common errors:
the names in the %MACRO and %MEND statements match, and there

is a %MEND for each %MACRO.


the number of %DO statements matches the number of %END
statements.
%TO values for iterative %DO statements exist and are appropriate.
all statements end with semicolons.
comments begin and end correctly and do not contain unmatched single
quotation marks.
macro variable references begin with & and macro statements begin with
%.
macro variables created by CALL SYMPUT are not referenced in the
same DATA step in which they are created.
statements that execute immediately (such as %LET) are not part of
conditional DATA step logic.
single quotation marks are not used around macro variable references
(such as in TITLE or FILENAME statements). When used in quoted
strings, macro variable references resolve only in strings marked with
double quotation marks.

11

macro variable values do not contain any keywords or characters that

could be interpreted as mathematical operators. (If they do contain such


characters, use the appropriate macro quoting function.)
macro variables, %GOTO labels, and macro names do not conflict with
reserved SAS and host environment keywords.
The SAS online help contains lots more detail on how to debug or fix these common
errors which I will not repeat here. But a particularly frustrating type of problem
deserves special attention. Sometimes when you run buggy SAS code using macro
facility statements SAS gets lost and does not seem to respond to even very simple
submissions of additional SAS statements. What is happening is that SAS thinks its in
the middle of either a macro statement or macro definition and is interpreting what you
are inputting as part of these. Until you can get the macro statement or macro
definition to be viewed as done you are stuck. One solution is to just save what you
can, close down SAS, and start SAS up again. But sometimes you dont want to do this
when you are in the middle of a long SAS session with lots of temporary data sets, open
SAS libraries, etc.
One way you can run into this kind of problem is through open code recursion. This
usually happens when you are creating a macro variable with a %let statement and
forget a semicolon, and then reference the variable you were creating in the next
statement. If you do this you should get an error statement about open code recursion
being detected. The first thing you can do is submit just a single semicolon in an
attempt to end the original %let (or other offending) statement. If that does not work
you can try to fix things by repeatedly submitting the following:
*'; *"; *); */; %mend; run;
Until you get the following statement in the SAS log:
ERROR: No matching %MACRO statement for this %MEND statement.
A similar kind of problem can occur when you forget to match a %MACRO statement
with a %MEND statement. Then all subsequent text is just considered to be part of the
macro. Fixing the error and resubmit does not solve the problem during the current
SAS session because the fixed macro is viewed as being nested within the still
incomplete original macro. You can first try to solve this problem by repeatedly
submitting %MEND statements until you get a message about no matching %MACRO
statement. There are, however, other problems when writing macro code that can lead
to similar symptoms including unmatched quotes or unmatched parenthesis. If you can
figure out the error you might be able to figure out what to submit to end things. A
generic approach would be to repeatedly submit:
*'; *"; *); */; %mend; run;

12

Things get complicated with these kinds of errors because one problem often cascades
into additional ones because code is not being interpreted in the context you expected it
to be.
In addition to checking for common errors and good programming practice there are
some tools to help. You already saw the %put which allows you to write statements
including resolved macro variables to the SAS log. You can also set some SAS system
options to generate lots of output about what is happening and how things are being
resolved. Perhaps the most useful of these are MLOGIC, MPRINT, and
SYMBOLGEN.
MLOGIC traces the flow of execution of your macro, including resolution of
parameters, the scope of variables (global or local), conditions of macro expressions
being evaluated, number of iterations for loops, and the beginning and end of each
macro execution. MLOGIC is useful when a bug lies in the program logic. MLOGIC
can produce lots of output so you probably only want to turn it on when you really need
it.
MPRINT writes each SAS statement generated by a macro to the SAS log. This can be
very useful in finding cases where your macro is generating SAS code in a manner you
did not expect. Again this can produce very large log files and you probably only want
it on for debugging purposes.
SYMBOLGEN tells you what each macro variable resolves to each time a variable is
resolved by writing messages to the SAS log. Because it produces a statement for every
resolution it is sometimes easier to just use %put when you suspect you know which
statements and macro resolutions are the problem.
You turn these options on by using the SAS statement:
OPTION xxx;
where xxx is either MLOGIC, MPRINT, and SYMBOLGEN. You can turn these off
by submitting another OPTION statement with xxx being NOMLOGIC, NOMPRINT,
or NOSYMBOLGEN.
Even More on Resolving Macro Variables
Suppose you had created a series of macro variables with the same prefix, distinguished
by a series of numbers, say: myvar1, myvar2, myvar3,
Now (say in the middle of a loop) you want to access the correct one of them based on
the value of the macro variable i.
If you wrote &myvar&i you would probably get an error because SAS would attempt
to resolve myvar and then resolve i and concatenate them, rather than concatenate

13

the text myvar with the value of the variable i. The solution is to use a double &,
which SAS refers to as indirect referencing: So you would write: &&myvar&i. When
SAS encounters it actually makes two passes through to interpet this code. The first
time through it converts && to just &, and then continues reading in (and resolving
additional macro variables as needed), then attempts to resolve the result. So after the
first pass &&myvary&i might become &myvar3 (if i=3), and then the value of myvar3
would be found. The same basic logic applies if you use more than two &s. E.g., say
the macro variable varname had a value of myvar3. If you used &&&varname, the first
two && would be converted into a single &, &varname would be resolved to myvar3
and concatenated with the &, and then the result of the first pass, &myvar3 would be
resolved. This is useful when the value of one macro variable is the name of another
macro variable. This is one way to pass the names of sas macro variables, rather than
their values, to a SAS macro. This is useful when the values are long and especially if
they contain commas.
Below is an example of code using &&&:
/* In following teststring imbedded blanks are included */
%let teststring=%str(year depthcat year*depthcat,
year);
/* Value of stringref is just the name of the previous macro var */
%let stringref=teststring;
/* %put statements for debugging/demo purposes */
%put here is '&stringref:' &stringref;
%put here is '&&stringref:' &&stringref;
%put here is '&&&stringref:' &&&stringref;
%put here is '&teststring:' &teststring;

Using this technique:


/* Next statement shows how to deal with macro variable
whose value is name of another macro variable and resolve value of
the second variable AND then how to select an element of that
string; */
%let testmod=%qscan(&&&stringref,2,',');
%put &testmod;

This next example shows a case where we create new macro variables with names built
from the values of two other macro variables. This can be useful when creating macro
variables in a general purpose macro in a situation where you do not know in advance
what their names should be.
/* This example creates a set of global macro variables
with names of testvar1, testvar2, ... testvar5 and sets values of
1, 2, ...5 to them */
%let prefix =testvar;
/* Need to make and run a macro because %do is not valid in open code
*/
%macro makevars;
%do i=1 %to 5;
%Global &prefix.&i;
%let &prefix.&i=&i;
%end;

14

%mend;
%makevars;
/* Just checking we got the intended results ! */
%put &testvar1 &testvar2 &testvar3 &testvar4 &testvar5;

Just a bit more on macro quoting


The following special characters and mnemonics can mean something in the macro
language. If they appear in a string you may need to mask them if you want them to
be considered part of the string rather than a macro instruction
blank

LT

GE

AND

GT

--

OR

IN

NOT

, (comma) /

EQ

&

'

NE

<

"
>
LE
The kind of problems that can arise is illustrated by:
%let print=proc print; run;; /* ERROR */
This really repeats the issue we saw before when making a macro variable a block of
SAS statements. The problem is that the intent is to assign proc print; run; to print
but the first semicolon would be interpreted as the end of the %let statement. For this
example one of the simplest quoting functions, %str, which we have seen before, can
solve the problem.
%let print=%str(proc print; run;);
The most commonly used macro quoting functions are:
%STR and %NRSTR
%BQUOTE and %NRBQUOTE
%SUPERQ

The functions with N do the same thing as the functions without the N except they
mask the % and &. So if you want % and & to be part of the string you should use
the N version. But if you want the macro variables resolved you should not. The
functions with a B will treat single unmatched quotation marks and parentheses as
part of a string. %superq works a bit different than the other functions in that it takes a

15

macro variable as an argument, returns the value and does not attempt to resolve macro
references in the value.
Logical Expressions and Conditional Execution
Macros allow for if statements with the following syntax:
%IF expression %THEN statement;
The expression in the above can include things like
&first=&second or &first>&second . While the macro facility is essentially a text
based system it will temporary interpret the macro variables as integer numbers in such
expressions. If you need to have logical evaluation of decimal (floating point) numbers
(or missing values are involved) you need to use the %sysevalf function. E.g., like:
%if %sysevalf(&first>&second) %then %put &first is greater than
&second;

Accessing and changing macro variable values during data step


There are times when you either want to assign a macro variable value to a data set
variable, or you wish to assign a data set varibles value to a macro variable or use the
data set variables value to influence how a macro proceeds. Thus we need to be able
to communicate between macro variables and data set variables.
Let us first consider setting the value of a data set variable to the value of a macro
variable. This is basically straightforward. An example would be:
/* assigning a macro variable value to data set variable */
Data cat127;
Input a b;
Cards;
1 2
3 4
;
%let testval=127;
Data cat&testval;
Set cat&testval;
cat=&testval;
run;
proc print data=cat127;
run;

Sometimes you might want to use the symget function instead. In the above dataset
this would be:
Data cat&testval;

16

Set cat&testval;
cat=symget('testval');
run;

The symget function puts the value of testval into cat, and does not try to resolve the
value before doing this, which is useful in some situations.
Grabbing a data set variable value and assigning it to a macro variable is a bit more
tricky. In this case you cannot use a simple assignment statement like %let test=b
because this get resolves before the data step is even executing and so test is just set to
b not to a value of the data set variable b. Here you need to call the symput routine.
Symput is useful for either assigning the value of a data set variable to a macro
variable, or assigning a value to the macro variable conditional on the value of the data
step variable. The basic syntax is CALL SYMPUT(macro-variable, value); macrovariable is typically the name of a macro variable enclosed in single quotes. Value can
be name of a data set variable. If so the value of the value of the macro variable is set
equal to the value of the data set variable. If value is a string enclosed in single
quotes, that string becomes the macro variable value. If you do this conditionally
depending on a data set variable value then you can set the macro variable based on
those conditions. E.g., you could set the macro variable to the value of b when a=1;
If macro-variable is the name of a character variable in the SAS data set rather than a
string in quotes, then macro variables are created corresponding to each name. This is
really useful if the SAS data set is basically a list of macro variable names and the
values you want to assign to those macro variables.
For those who are heavy Proc SQL users, the select statement is the analog of the call
symput routine for data steps. An example application might be:
proc sql;
select min(aicc) into: min_aic from aics;
quit;

This code finds the minimum of the variable aiccc in the data set aics and assigns this
as the value for the macro variable min_aic.

17

Potrebbero piacerti anche