Vous êtes sur la page 1sur 16

Master Macro Variables - by Examples

Sophia Yue, Bank of America, Phoenix AZ

ABSTRACT
Quite often, it is required to use macro variables in a loop. However, SAS doesn't have the ability to define a macro variable as
an array. Using a macro variable with a list of values to define an array variable in DATA step, using SQL (Structured Query
Language) to store row values in a list of macro variables, or using SQL to storing values of all rows in one macro variable are
ways to tackle it.
Macro variables enable us to dynamically modify codes via symbolic substitution. It allows us to keep one copy of code for
different applications/purposes. The paper will cover the example to define macro variable with the value of variable name to
generate code dynamically for different scenarios.

INTRODUCTION
The SAS macro facility is an extremely useful part of the SAS System and can be used to expand and customize the
functionality of the SAS System and reduce the amount of text entering for common tasks. The macro allows modularizing
code into portable and reusable program units. However some manipulations might be required to achive the goals. The
paper will cover four parts and use examples for explanation.
1. Use SYSPARM and the Forward Scan and Rescan Rule to generate code dynamically
2. Use macro variable with a list of rank distribution to calculate the PSI (Population Stability Index)
3. Apply macro pseudo-array to invoke macro utility defined in Part 2 three times
4. Use the PROC SQL to store all rows in one macro variable and all rows in a range of macro variables

The paper elaborates a little bit of following topics to help readers understand the examples better and reinforce/gain/expend
knowledge of macro:
1. Macro concepts
2. Scopes of macro variables
3. Debugging macro errors
4. Macro functions
5. Autocall facility and autocall macros
6. Data step interfaces with the macro facility
7. PROC SQL vs. DATA step
In the paper, angle brackets, <>, identify optional arguments. Any argument that is not enclosed in angle brackets is required.

MACRO GENERAL CONCEPTS


The macro processor and the macro language are two components of the macro facility. The macro language defines the
syntax of macro code and the macro processor performs the text substitution before the SAS code is compiled and executed.
The SAS macro code consists of two basic parts: macros and macro variables. It depends on the content, the &NAME might
refer to a macro variable or a macro variable reference and %NAME might refer to a macro function or a macro call. The
&NAME can be a user defined macro variable or a SAS automatic macro variable created by the macro processor like
&SQLOBS, &SYSDAY, &SYSPARM, etc. The &NAME. is interchangeable with &NAME and most macro programmers only
add the period when it is required or needed to minimize confusion. The dot is required in mdl_&mdl_typ._scr. Without a dot,
the macro process will try to resolve &mdl_typ_scr. It would result in an error or get an unexpected result.

The %NAME can be a SAS macro function like %SCAN, %CMPRES, %SYSFUNC, etc.; or a macro statement which instructs
the macro processor to perform an operation like %LET, %IF, %DO; %END, etc.; or a user defined macro which starts with
%MACRO statement and ends with %MEND statement. The general form of a macro is

%MACRO macro-name;
macro-definition
%MEND macro-name;

The macro-name specified in the %MEND statement must match the macro-name specified in the %MACRO statement. The
macro-name in the %MEND statement is optional. For debugging purpose, it is recommended. The macro-definition is a piece
of a program that may contain complex logic including complete DATA and PROC steps, macro calls and macro statements
such as %DO, %END, and %IF-%THEN/%ELSE. When SAS compiles program text, &NAME and %NAME trigger macro
processor activity to resolve macro variables and macros and generate standard SAS code.

Page 1 of 16
In SAS, a single ampersand is used to return the value of a macro variable. When multiple ampersands precede a name
token, the macro processor resolves two ampersands to a single ampersand and then re-scans. This is known as the Forward
Scan and Rescan Rule or indirect macro reference.

Meta-programming refers to the ability to write a code to generate another code at runtime. Since the SAS program with macro
code uses a code/program, the macro(s) and macro variable(s), to write a program, it can be identified as meta-programming.

MACRO SYSTEM OPTION


The MACRO system option enables SAS to recognize and process macro language statements, macro calls, and macro
variable references. This option is usually turned on by default, but it may be turned off by turning on the option NOMACRO.
By setting NOMACRO on, there is no overhead of checking for macros or macro variables. If the macro facility is not used in a
job, the user might consider turning off the MACRO system option to improve the performance slightly. The user might use
the following statements to check if MACRO system option is on. The log file will show ‘MACRO’ if the MACRO system option
is on. It is required to use %SYSFUNC to access the SAS base function GERTOPTION. Please refer to the details of
%SYSFUNC in the session of Using Portable SAS Language Functions With %SYSFUNC.
%let MACRO=%sysfunc(getoption(MACRO));
%put &MACRO; /* The log file will show ‘MACRO’ if the MACRO system option is on */

The user might use PROC OPTIONS to check if the MACRO system option is on.
PROC OPTIONS OPTION = MACRO; RUN;

CREATING A MACRO VARIABLE WITH %LET


The %LET statement is the easiest/simplest way to define and assign a value to a macro variable. The syntax is %LET macro-
variable =<value>;
The macro-variable is either the name of a macro variable or a text expression that produces a macro variable name. Value is
a character string or a text expression. Omitting value produces a null value (0 characters). Leading and trailing blanks in
value are ignored. To make them significant, enclose value with the %STR function. A period or dot can be used to terminate
the name of the macro variable. Sample %LET Statements:
%let a=; /* The &a will resolve to null value*/
%let name = city;
%let &name = New York; /* The &city will resolved to New York */
%let state = New York;
%let address = The city is &city in the state of &state;

The &address will resolve to The city is New York in the state of New York. The following %LET statement defines the CSV
file location and name. The dot after &workdir is not necessary. Two dots are required between &scr_dsn and csv. The first
dot is used as a macro variable terminator and the second dot is used to separate the base filename from the file extension
csv.
%let csv_file = &workdir./&scr_dsn..csv;

%SCAN
A macro language function processes one or more arguments and produces a result. All macro functions start with % and can
be used in both macro definitions and open code which is everything outside a macro. Use the macro %SCAN function to scan
for words in macro variable values. The syntax is “%SCAN(macro_var_list, word_number, <word_delimiter>)” where the
word_delimiter is optional. The %SCAN function searches argument and return the nth word. A word is one or more
characters separated by one or more delimiters. In the following example, the &SYSPARM has the value "dep:1506". The
%SCAN will scan words from the macro variable &SYSPARM with delimiter as “:”. The %SCAN assigns the first word value
“dep” to the macro variable mdl_type and the second word “1506” to the macro variable yymm.
%let mdl_typ = %lowcase(%scan(&sysparm,1,':'));
%let yymm = %scan(&sysparm,2,':'); /*scan the second word and assign the value to the macro variable yymm */
In ASCII environments, the default delimiters are:
blank ! $ % & ( ) * + , - . / ; < ^¦

The %SCAN does not mask special characters or mnemonic operators, listed below. The %QSCAN function is similar/close to
%SCAN with the ability to mask special characters or mnemonic operators.

Page 2 of 16
& % ' " ( ) + - * / < > = ¬ ^ ~ ; , blank
AND OR NOT EQ NE LE LT GE GT

EXAMPLE 1: GENERATE CODE DYNAMICALLY


The purpose of the code in Example 1 is to create a CSV (Comma Separated Values) file from a model scored dataset. The
code is parameter driven and it is based on the parameter to generate the code accordingly/dynamically. In the example, the
parameter would be DEP (deposit) or CRD (credit). The SYSPARM is an automatic macro variable and it can be updated
before execution.
The code will retrieve the parameter from SYSPARM and generate code for deposit or credit models. Three ampersands will
be used to reference a macro variable indirectly. By applying the tool and tips, it would allow using the same code to create the
code dynamically for different purposes.

1. The SYSPARM is used at the invocation of every SAS job or session and provides dynamic coding. The SYSPARM is
one of the tools to enhance the SAS code and reduce the overhead of tracking source code changes.
 The SAS code “cr_mdl_csv.sas” runs on a UNIX operating environment and the SYSPARM is specified as a
command line argument, e.g. the run command example for the deposit model:
sas cr_mdl_csv.sas -sysparm "dep:1506" -log /mylib/log/cr_mdl_csv.sas.dep.log

2. The macro function %CMPRES and %QCMPRES compress multiple blanks and remove leading and trailing blanks. If the
argument might contain a special character or mnemonic operator, use %QCMPRES. It is based on the value in
mdl_type to decide the name of input and output files. The output variables of the CSV file are different between deposit
and credit models. The code defines two macro variables and uses %CMPRES to compress multiple blanks and remove
leading and trailing blanks.
 dep_var with value of variables required by the CSV file for deposit model
 crd_var with value of variables required by the CSV file for credit model

3. Triple ampersands can be used if the value of the macro is itself the name of another macro variable. When the macro
processor encounters multiple ampersands, its basic action is to resolve two ampersands to one ampersand. Using the
Forward Scan and Rescan Rule or an indirect macro variable reference, it forces the macro processor to scan the macro
variable reference more than once and resolve the desired reference on the second, or later, scan. In the case, the value
of one variable is the name of a second variable whose value would be retrieved. By using three ampersands to define a
macro variable, it will return the variable name instead of the value to the macro variable.
If the macro variable mdl_type resolves to “dep”, the macro variable scr_var from the following code would resolve to
&dep_var not the value of dep_var and then into the SAS statements contained in the macro variable dep_var. Thus, the
long value of macro variable dep_var is stored only once. Using triple ampersands increases the flexibility of the code.
Using triple ampersands, the macro processor only needs to store a long macro variable value once and it increases the
efficiency of the macro processor.
%let mdl_typ = dep;
%let dep_var=%cmpres(acct_no scr_mdl_dep_no rnk_mdl_dep_no);
%let scr_var = &&&mdl_typ._var;

Complete code of cr_mdl_csv.sas


%let mdl_typ = %lowcase(%scan(&sysparm,1,':'));
%let yymm = %scan(&sysparm,2,':');
%let workdir = /mylib;
libname workdir "&workdir";
%let scr_dsn = mdl_&mdl_typ._scr_&yymm;
%let dep_var = %cmpres(
acct_no
scr_mdl_dep_no
rnk_mdl_dep_no);
%let crd_var= %cmpres(
crd_no
scr_mdl_crd_no
seg_mdl_crd_cd);
%let scr_var = &&&mdl_typ._var;
%let csv_file = &workdir./&scr_dsn..csv;
FILENAME csvfile "&csv_file";
Page 3 of 16
data _null_;
set workdir.&scr_dsn ( bufno = 200 );
file csvfile DSD DLM =',' LRECL=2000;
put &scr_var;
run;

Notes for Example 1


1. The proceeding code demonstrates using three ampersands to generate code dynamically.
2. The code below shows how to use the procedure PROC EXPORT to create a CSV file. Bear in mind, the DATA steps
read and modify data while the PROC steps analyze data, perform utility functions, or print reports.
3. By default, variable names are written to the first row of the CSV file when using PROC EXPORT.
4. Use the PUTNAMES=NO statement to prevent variable names from being written to row 1 of the CSV file.
%let mdl_typ = %lowcase(%scan(&sysparm,1,':'));
%let yymm = %scan(&sysparm,2,':')
%let workdir = /mylib;
libname workdir "&workdir";
%let mdl_scr_dsn = mdl_&mdl_typ._scr&yymm;
%let mdl_csv_file = &workdir./&mdl_scr_dsn..csv;

proc export data=workdir.&mdl_scr_dsn


outfile="&mdl_csv_file"
dbms=csv
replace;
putnames = no;
run;

SCOPES OF MACRO VARIABLES


Macro variables can have two scopes either local or global. Generally, a macro variable is local if it is defined inside a macro
and it is global if it is defined in open code which is outside a macro. A global macro variable can be used anywhere in a
program and local macro variable can be used only inside the macro. Both the %GLOBAL statement and the %LOCAL
statement create macro variables with a specific scope. The %GLOBAL statement creates global macro variables in the global
symbol table exist for the duration of the session or job. The %LOCAL statement creates local macro variables in the local
symbol table that exist only during the execution of the macro that defines the variable. A %LET statement creates a macro
variable. If the %LET statement is outside the macro, the macro variable would be a global macro variable. The following
example demonstrates using macro statement %GLOBAL, %LOCAL, %LET and macro parameters to define macro variable
and their scope:
%let city_src = New York; /* The city_src is defined outside macro. It is a global macro variable */
%global city_dest; /* Declare city_dest as a global macro variable */
%macro city_xcg (city1, city2); /* Two parameters for macro city_xcg. City1 and city2 are local */
%local city_dest; /* Declare city_dest as a local macro variable. Any change of city_dest will remain inside the macro */

%put Invocation starts city_src &city_src city_dest = &city_dest;


%let city_src = &city1;
%let city_dest = &city2;
%put During invocation city_src &city_src city_dest = &city_dest;
%mend city_xcg;
%city_xcg(Phoenix, Glendale); /* Invoke macro. Pass Phoenix to macro variable city1 and Pass Glendale to macro variable city2 */
%put After invoking macro city_src &city_src city_dest = &city_dest;

During invocating the macro city_xcg, the macro variable city_dest has the value as Glendale. The value will not carry over
after invocation. The followings will show in the log file:

Invocation starts city_src New York city_dest =


During invocation city_src Phoenix city_dest = Glendale
After invoking macro city_src Phoenix city_dest =

DEBUGGING MACRO ERRORS


Incorrect scope would cause incorrect results and the stress to debug. The %SYMGLOBL function and %SYMLOCAL function
are useful to check the scope of macro variables. The %SYMGLOBL function with syntax as %SYMGLOBL(macro-variable-
name) searches enclosing scopes for the indicated macro variable and returns a value of 1 if the macro variable is found in the
Page 4 of 16
global symbol table, otherwise it returns a 0. With the same token, the %SYMLOCAL(macro-variable-name) can be used the
check if the macro variable is local in scope. Foe example:
%put %SYMGLOBL(var1);
%put %SYMLOCAL(var2);

The %PUT statement writes text or macro variable information to the SAS log file and it is helpful in debugging to track
problems. The syntax is %PUT <text | _ALL_ | _AUTOMATIC_ | _GLOBAL_ | _LOCAL_ | _USER_> . The %put statement can
write lists of macro variables in the log.

 %PUT _ALL_ will list all macro variables.


 %PUT _GLOBAL_ will list all the global macro variables.
 %PUT _AUTOMATIC_ will display all automatic variables.
 %PUT _USER_ describes the user-generated macro variables in all scopes.

Three SAS system options MLOGIC, MPRINT, SYMBOLGEN control the macro processor to display text generated by the
execution of macros and/or by the resolutions of macro variable references. It is a good idea to turn on these options while
developing/testing a code or debugging macros.

 The MPRINT system option displays the SAS statements that are generated by macro execution.
 The SYMBOLGEN system option displays the results of resolving macro variable references.
 The MLOGIC system option causes the macro processor to trace its execution and to write the trace information to the
SAS log.
The MFILE system option directs MPRINT output to an external file. The external file must be assigned the fileref MPRINT.
The following example, turn on the options and define external file name for mprint.
OPTIONS MLOGIC MPRINT SYMBOLGEN MFILE ;
filename mprint "workdir/macro_mprint.txt";

If there is a need to turn on the options, it is highly recommended placing the option statement on top of a code. The default
settings for these options are NOMPRIN, NOSYMBOLGEN, NOMLOGIC and NOMPRINT. If the error/warning message is
odd, the user might GOOGLE the message for help.

MACRO FUNCTIONS
A Base SAS function or a macro language function performs a computation or system manipulation on arguments and returns
a value. All macro functions can be used in both macro definitions and open code. All arguments and return values for macro
functions are text values and the text arguments are not enclosed in quote marks. Macro functions include

 Character functions to change character strings or provide information about them like %Index, %Length, %SCAN, etc.
 Evaluation functions to evaluate arithmetic and logical expressions like %EVAL, %SYSEVALF,
 Quoting functions to mask special characters or mnemonic operators like %QSCAN, %QSUBSTR, %UPERCASEQ, etc.,
 Other functions like %SYSFUNC, %SYSGET, and %SYSPROD.

AUTOCALL FACILITY AND AUTOCALL MACROS


The user might use SAS macro %CMPRES to get rid of unnecessary blanks in a string.When the option MLOGIC is on, the
log will show the following message like this:
MLOGIC(CMPRES): This macro was compiled from the autocall file /sas/9.4/prod/install/SASFoundation/9.4/sasautos/cmpres.sas

The message shows that %CMPRES is autocall macro and the location to store the macro. An autocall library is a central
location to store macros to be shared by programs and programmers. When invoking a autocall macro, the uses doesn’t need
to specify the location of autocall library or include the code in the calling program. With the system option MAUTOSOURCE
on, the autocall facility allows the user to call macros stored in autocall libraries. The selected SAS autocall macros are
%CMPRES, %QCMPRES, %COMPSTOR, %DATATYP, %KVERIFY, %LEFT and %QLEFT, %LOWCASE and
%QLOWCASE, etc. The user can treat the autocal macros like normal macro and no needs to worry what behinds the scene.

The following macro functions or autocall macros work in the same way as the Base SAS functions of the same name:

 Macro functions - %INDEX, %STR, %SCAN, %VERIFY, %SUBSTR, etc.


 Autocall macros - %LOWCASE, %UPERCASE , %TRIM, %LEFT, %VERIFY, etc.

Page 5 of 16
When SAS is installed, the autocall libraries are included in the value of SASAUTOS system option in the system configuration
file. The SASAUTOS with library-specification specifies the location of autocall libraries. The syntax is SASAUTOS= library-
specification or SASAUTOS=(library-specification-1 . . . , library-specification-n).
The library-specification can be a fileref or the pathname in quotes. Multiple libraries can be referenced using ( , , ,). For
example,
SASAUTOS = (myauto, sasautos)
SASAUTOS=(sasautos, '$USERMACRO'). /* The SASMACRO is an environment variable. */

The user can use %sysget function to retrieve the value of an environment variable like this
%let sasmacro= %sysget(USERMACRO);

A user-written common used macro is appropriate to store in an autocall library. The better practice is to separate the location
to store the user defined autocall macros from the location to store the macro codes provide by SAS. The sasautos specified
in SASAUTOS option tells autocall facility to search SAS supplied macro. If a user redefines SASAUTOS, make sure to
include sasautos in SASAUTOS option.

The following user defined autocall macro m_get_opt will save in /mylib/common_code/m_get_opt.sas.
%macro m_get_opt(opt_name);
%let get_opt_name=%sysfunc(getoption(&opt_name));
%put &opt_name is &get_opt_name;
%mend m_get_opt;

The following code will invoke a user defined autocall macro m_get_opt in /mylib/common_code/m_get_opt.sas.
1. Use filename to define the fileref uautocal.
2. Define SASAUTOS with library-specification-1 = sasautos and library-specification-2 = uautocal .
3. Invoke user defined autocall macro m_get_opt
4. Invoke SAS autocall macro cmpres

filename uautocal '/mylib/common_code';


options SASAUTOS = (sasautos, uautocal) ;
%m_get_opt(SASAUTOS);
%let city_aft= %cmpres( new york );
%put &city_aft;

The sasautos is required in the option of SASAUTOS. Otherwise, the sas autocall macro cmpres will not be resolved.

The following are options to save user defined macro:


1. Define the macro inside the calling code
2. Save the macro in an external flat file. Use %INCLUDE to include the file
3. Save the macro in an autocall library and
4. Save the pre-complied macro and use Stored Compiled Macro Facility to resolve the macro call. The paper will not cover
this topic.

In Example 2, the macro ‘calc_psi’ would be inside the calling code. In Example 3, the macro ‘calc_psi’ would be stored in an
external file and the calling program needs to include the file inside the calling code .

USING PORTABLE SAS LANGUAGE FUNCTIONS WITH %SYSFUNC


The %SYSFUNC is a special macro function to provide access to SAS language functions or user-written functions with the
macro processor. The %SYSFUNC can be used to perform most host-specific operations to open and close SAS data sets,
test data set attributes, or read and write to external files. Using %SYSFUNC to access portable SAS language functions can
save a lot of macro coding and make code more efficient. When there is not an equivalent SAS Macro Language function to a
Base SAS function, use %SYSFUNC to access to SAS language functions. The following code will use %SYNFUNC to access
Base SAS function MDY, INPUTN and PUTN. These functions do not have equivalent macro functions. The MDY function
returns a SAS date value from month, day, and year values. The INPUTN function specifies a numeric informat at run time
and the PUTN function specifies a numeric format at run time.
%let mth = 8;
%let day = 16;
%let year = 2015;

data _null_;
birthday=mdy("&mth","&day","&year"); /* Need double quotation to resolve macro variables */
put birthday=; /* Log file shows birthday= 20316 (SAS date for 16AUG2015) */
put birthday= date9.; /* Log file shows birthday=16AUG2015 */
Page 6 of 16
run;

%let birthday = %sysfunc( mdy(&mth,&day,&year)); /* Use %SUSFUNC to call Base SAS function MDY */
%put birthday= &birthday; /* Log File shows birthday= 20316 (SAS date for 16AUG2015) */
/* Base SAS function inputn specifies a numeric informat at run time */
/* BASE SAS function putc specifies a numeric format at run time */
%let daybirth = %sysfunc(putn(%sysfunc(inputn(&birthday, best9.)), date9.));
%put daybirth = &daybirth; /* Log file shows daybirth=16AUG2015 */

The %SYSFUNC can call all the DATA step SAS functions except DIF, DIM, HBOUND, INPUT, LAG, LBOUND, PUT,
RESOLVE and SYMGET. The %SYSFUNC is the same as %QSYSFUNC with one difference. The %SYSFUNC does not
mask special characters or mnemonic operators in its result. The %QSYSFUNC does.

MACRO PARAMETERS
Writing the same or similar SAS statements over and over is inefficient and awkward. Consider writing a macro for a piece of
code and use it repeatedly. User defined macros provide powerful tools to

 Simplify code
 Build utilities for common tasks
 Hide complex code
 Share and re-use code

The %MACRO statement begins a macro definition while %mend marks the end. The general form of a macro is
%MACRO macro-name <(parameter-list)> </ option-1 <...option-n>> ;
macro-definition
%MEND macro-name;

The macro-name names the macro. A macro variable defined in parentheses in a %MACRO statement is a macro parameter
which would be referenced in the macro and local to the macro. The calling code assigns values to parameters and passes
information into a macro when invoking a macro. A parameter list can contain any number of macro parameters separated by
commas. Parameter-list can be positional parameter(s) or keyword parameter(s):

 <positional parameter-1><. . . ,positional parameter-n>


 <keyword-parameter=<value> <. . . ,keyword-parameter-n=<value>>>

The order of positional parameters in the parameter-list is not important. In the macro invocation, the order of the values
assigned to parameters must match the order specified in the %MACRO statement. A keyword parameter is a parameter
name following with an equal sign (=). A default value is specified after equal sign parameter list. Without specifying the
default value, the keyword parameter has a null value. Using default values enables a programmer to write more flexible
macro definitions and reduces the number of parameters that must be specified to invoke the macro. To override the default
value, specify the macro variable name followed by an equal sign and the new value in the macro invocation. If both positional
and keyword parameters appears in the parameter list, positional parameters must come first.

MACRO INVOCATION TYPES


Macros have three invocation types: name style, command style, and statement style. Name style invocation is the most
efficient because name style macros always begin with a %, which will trigger macro processor activity immediately. Macros
defined with the CMD option are command-style macros which would be executed from the command line of a SAS window.
Macros defined with the STMT option are called statement-style macros. For these two styles, time is wasted while the word
scanner determines whether the token should be sent. The user can use name style invocation for statement-style macros
and command-style macros.

EXAMPLE 2: MACRO UTILITY TO CALCULATE PSI


The PSI (population stability index) is to measure the stability of a specific score and/or variable by comparing a data sample
from one time period (Base Data) to another (Target Data). It is widely used to monitor the integrity of data and scorecard.

Since the code to calculate the PSI would be used in Example 3, it is appropriate to define the code as a macro. The macro
code “calc_psi” uses four positional parameters to calculate the PSI:

 scr_dsn : scored dataset with ranks


 rank_var : rank variable name
Page 7 of 16
 psi_var : macro variable name to save psi
 base_pct : list of values of base rank distribution
The base_val defined from the calling program is a macro variable with a list of predefined values of rank distribution from the
base data. When invoking the macro program “cal_psi”, the value of base_val would assign to base_pct. The rank distribution
of target data will be created from the scored dataset by using PROC FREQ. The target rank distribution, pct_targ, will
combine with the base rank distribution, pct_base, derived from the macro variable base_pct and use the formula below to
calculate the PSI.
PSI = ∑ ( pct_targ/100 - pct_base/100) * (log(pct_targ/100) - log(pct_base/100))

Example 2 would define the macro utility “calc_psi” with the following functions to calculate the PSI.
1. The COUNTW is a Base SAS function to count the number of words in a character string. Since there is not an
equivalent SAS macro language function, use the function %SYSFUNC to access the Base SAS function COUNTW to get
the number of values defined in base_pct with delimiter as a space. Assign the value to no_base_val which will be used to
define the array size dynamically during DATA step execution.
%let no_base_val = %sysfunc(countw(&base_pct, %str( )));

2. Validate if the sum of values in base_pct is close to 100.


 The list of values defined in base_pct is assigned to an array and a numbered range list during DATA step execution.
 Use the SUM function with a variable list as an argument to get the total of values defined in base_pct.
3. The proc freq would get the percentage of rank distribution from the target scored dataset and create a work dataset
rankfrq_scored.
4. Combine base rank distribution with target rank distribution from rankfrq_scored into a work dataset “rankfrq” to calculate
the PSI.
 Assign the values from &base_pct to the array base_ary and assign the values from the array to pct_base.
 The _n_ is one of the SAS automatic variables which are created by SAS and can be used in DATA step. The _n_
indicates the number of times SAS has looped through the DATA step. It would be used to index array value for
base_ary.
pct_base = base_ary(_n_);

 Ignore the observations with rank value as missing.


5. Use PROC SQL with input as “rankfreq” and the SQL SUM function to calculate the PSI and assign the value to the
macro variable defined in the macro variable psi_var. The later session will cover the details of PROC SQL, SELECT
statement and INTO clause.
select sum(( pct_targ/100 - pct_base/100) * (log(pct_targ/100) - log(pct_base/100))) into :&psi_var from rankfrq

Code to Calculate the PSI

%macro calc_psi(scr_dsn, rank_var, psi_var, base_pct);


%global &psi_var;
%local no_base_val;
/* Invoke COUNTW to get number of values defined in &base_pct */
%let no_base_val = %sysfunc(countw(&base_pct, %str( )));
%put &no_base_val;

/* Validate if the sum of values in base_pct is close to 100 */


data _null_;
array base_ary(&no_base_val) base_1-base_&no_base_val (&base_pct);
pct_sum= sum(of base_1 - base_&no_base_val);
if ABS( pct_sum - 100) > 1 then
do;
put "ERROR: The sum of values from the base percent is " pct_sum;
put "It should be close to 100. Please investigate it.";
abort abend;
end;
run;

/* Create target rank distribution from the scored dataset */


proc freq data = &scr_dsn;

Page 8 of 16
tables &rank_var/out = rankfrq_scored (keep = &rank_var percent );
run;

/*Combine base and target rank distribution into rankfreq to calculate the psi */
data rankfrq ( keep = &rank_var pct_targ pct_base);
set rankfrq_scored ( rename =(percent = pct_targ ) where = ( &rank_var <> .) );
array base_ary(&no_base_val) _temporary_ (&base_pct);
percent_base = base_ary(_n_);
run;

/* calculate psi */
proc sql;
select sum((pct_targ/100 - pct_base/100)*(log(pct_targ/100)-log(pct_base/100)))
into :&psi_var
from rankfrq ;
quit;
%mend calc_psi;

libname workdir "/mylib";


%let rank_var = rnk_modl_dep;
%let base_val = 10.01 10.02 10.03 10.04 10.05 9.99 9.98 9.97 9.96 9.95;
%let scr_dsn = workdir.mdl_dep_scr;

/* Invoke calc_psi to calculate the psi */


%calc_psi(&scr_dsn,
&rank_var,
psi,
&base_val);
%put The PSI value is &psi;

Notes
1. The code to create the dataset “rankfreq” can be replaced with the following code. The code uses the SCAN function to
scan the macro variable list, uses the “_n_” to extract the individual value and assign it to pct_base. Since the macro
variable value is always character, it is required to use the INPUT function converting a character value to a numeric value
to calculate the PSI.
data rankfrq( keep = &rank_var pct_targ pct_base);
set rankfrq_scored ( rename =(percent = pct_targ) where = (&rank_var <> .));
pct_base = input(scan("&base_pct", _n_, ' '), best5.2) ;
put pct_base =;
run;

2. The example here is using fix base values to calculate the PSI. In reality, the base data could be the last month
data/scored dataset and the target data could be the current month data/scored dataset.
3. Usually, the PSI <=0.01. However, the user can define the PSI tolerance value. The PSI calculating from example 2 might
compare with the PSI tolerance value and send an email with warning message to the user if PSI > PSI tolerance value.
4. The macro “calc_psi” from Example 2 would be used by Example 3.

DATA STEP INTERFACES WITH THE MACRO FACILITY


Interfaces with the macro facility provide a dynamic connection between the macro facility and other parts of SAS, such as the
DATA step and the SQL procedure. An interface with the macro facility is not part of the macro processor but rather a SAS
software feature that enables another portion of the SAS language to interact with the macro facility during execution. Macro
processing happens before DATA step or SQL execution, the connection between the macro facility and the rest of SAS is not
usually dynamic. Facility interfaces allows connecting to the rest of SAS dynamically.

DATA step interfaces consist of the following eight tools that enable a program to interact with the macro facility during DATA
step execution.
1. The CALL EXECUTE routine allows the execution of a SAS macro from within a SAS DATA step.
2. The RESOLVE function resolves the value of a text expression during DATA step execution.
3. The CALL SYMDEL routine deletes the indicated macro variable named in the argument.
4. The SYMEXIST function returns an indication if the macro variable exists.
5. The SYMGET function returns the value of a macro variable during DATA step execution.
6. The SYMGLOBL function returns an indication if the macro variable is global in scope.
Page 9 of 16
7. The SYMLOCAL function returns an indication if the macro variable is local in scope.
8. The CALL SYMPUT routine assigns a value in a DATA step to a macro variable.
The SYMGLOBL function and SYMLOCAL function are similar to %SYMGLOBL macro function and %SYMLOCAL function
which are covered in the session of Debugging Macro Errors. The CALL SYMPUT routine takes a single dataset value and
assigns it to a macro variable. The routine either creates a macro variable whose value is information from the DATA step or
assigns a DATA step value to an existing macro variable. The syntax is CALL SYMPUT(argument-1,argument-2);
 The argument-1 specifies a macro variable that is assigned a value. If the macro variable does not exist, the routine
creates it. The macro variable must be in single or double quotes.
 The argument-2 specifies a character constant, variable, or expression that contains the value that is assigned.

The CALL SYMPUT places a value of a SAS variable inside a DATA step into a macro variable at run time. Since SAS does
not assign a value to the macro variable until the DATA step executes, the macro variable created from CALL SYMPUT can't
be used in the same DATA step. The CALL SYMPUT allows sharing the data across DATA and PROC step or pass the data
from DATA and PROC to a macro outside of DATA and PROC step.

The user can use SYMGET function or RESOLVE function to reference the macro variable defined in another DATA step via
CALL SYMPUT function. The syntax of SYMGET is SYMGET(argument) where the argument is the name of a macro variable
within quotation marks but without an ampersand. The syntax of RESOLVE is RESOLVE (argument) where argument is a
macro expression. There are three types of macro expressions: text, logical, and arithmetic. A text expression is any
combination of text, macro variables, macro functions, or macro calls. Below is an example to use CALL SYMPUT to define
three macro variables and use SYMGET function and RESOLVE function to resolve the value of macro variables. The
SYMGET function resolves only a single macro variable but RESOLVE resolves any macro expression.

data _null_;
city3 = "Glendale";
call symput('city1', 'New York'); /* Define a macro variable with value as NEW YORK */
call symput('city2', "Phoenix");
call symput('city3', city3); /* Define a macro variable with value as the value from DATA variable city3 */
run;
data _null_;
format all_city $100.;
city=symget('city1'); /* Use SYMGET to resolve macro variable city1; & is not required */
/* The log file will show all_city=New York Phoenix Glendale sysdate is 16AUG15
The argument of RESOLVE is more flexible than SYMGET */
all_city=resolve(trim(city) || ' ' || "&city2" || ' ' || "&city3" || ' sysdate is ' || left("&sysdate") );
put all_city=;
run;

The CALL EXECUTE routine allows passing the values from DATA step to a macro. CALL EXECUTE is useful when
executing a macro conditionally or within a loop. The syntax is CALL EXECUTE(argument). The argument is a character
string, enclosed in quotation marks. Use concatenation operator || to concatenate a variable name as a parameter for the
macro from data step. Do not enclose the name of the DATA step variable in quotation marks. Examples
call execute('%salary'); /* Invoke %salary within a data step; Without passing a parameter */
call execute('%inventory(‘ || dept || ‘)’); /* Invoke %inventory within a data step. The value of dept from a DATA step would be a parameter */

The following example, invoke the macro m_test outside DATA step and within DATA step. The example shows how to pass
parameters with CALL EXECUTE.
%macro m_test(a1, b1, c1);
%let res = &a1. &b1. &c1;
%put a1= &a1 b1= &b1 c1= &c1 res=&res;
%mend;

%let a = walk;
%let bb= fast;
%let c= slow;
%m_test(&a, too, &c); /* After invoking the macro, the log file shows a1= walk b1= too c1= slow res=walk too slow */

data _null_;
aa="very";
/* After invoking the macro, the log file shows a1= run b1= very c1= fast res=run very fast */
call execute ('%m_test(run, ' || aa|| ', &bb )'); /* Do not enclose the DATA step variable aa in quotation marks */
run;
Page 10 of 16
EXAMPLE 3: MACRO PSEUDO-ARRAY
There is no macro equivalent to the ARRAY statement. SAS doesn't have the ability to define a macro variable as an array.
The macro array is an implied pseudo-array by defining a series of macro variables that share the same prefix and a numeric
suffix, for example, AA1, AA2, AA3, etc. which can be dealt with iteratively according to the index.
The purpose of Example 3 is to use macro arrays to invoke the macro “calc_psi” defined in Example 2 to calculate the PSI for
three models. In Example 3, there are macro variables pct_base1, pct_base2, pct_base3 which will be used in %DO-%END.
Example 3 covers the following functions:
1. Define macro arrays from DATA _NULL_ step
 Use the do loop and CALL SYMPUT routine to assign values to macro arrays mdl_desc, psi_tol, scr_var, and
rank_var.
 The values assigned to the macro arrays psi_tol and mdl_desc are defined from the ARRAY psi_tol and mdl_desc.
 Using the TRIM, LEFT, COMPRESS and COMPBL functions is recommended when creating macro variables to
remove possibly trailing or leading blanks. In the following code with i = 1, the mdl_id would be dep01, the value of
macro variable mdl_desc1 would be dep01-Money Market.

mdl_id = "dep" || put (i, z2.); /* required to have 0 before i */


call symput('mdl_desc'|| put (i, z1.), mdl_id || " - " ||trim(left(mdl_desc(i))));

2. Call the macro “calc_psi_loop” to use %DO-%END to invoke the macro “calc_psi” three times.
 Would use indirect macro variable reference, &&pct_base&I and &&rank_var&I as parameters to invoke “calc_psi”.
 To reference a macro array, it is required && before the macro array variable and follows with &I where I is the macro
variable to reference a variable in the series of macro variables.
 Using &pct_base&I as a parameter is incorrect, there will be a warning message in the log file: WARNING: Apparent
symbolic reference PCT_BASE not resolved.
 The macro “calc_psi_loop” doesn’t have parameters. The values of macro variables defined in the calling program
will pass to the macro.
 Please refer to Example 1 for more details of indirect macro variable reference.

Code to Use Loop to Calculate the PSI


%macro calc_psi_loop;
%do i=1 %to &no_mdl;
%calc_psi(&scr_dsn,
&&rank_var&i,
psi&i,
&&pct_base&i);
%put The PSI value for model ID &&mdl_desc&i with score var &&scr_var&i is &&psi&i;
%put The psi tolerance value is &&psi_tol&i ;
%end;
%mend calc_psi_loop;

%include "/mylib/common_code/calc_psi.sas”; /* External file for macro calc_psi */


%let workdir=/mylib;
libname workdir "/mylib";
%let no_mdl = 3;
%let pct_base1 = 28.37 14.45 9.46 7.9 6.63 6.27 5.45 6.06 6.96 8.46;
%let pct_base2 = 17.27 13.65 10.24 10.37 9.04 8.75 8.6 7.47 7.67 6.94;
%let pct_base3 = 17.07 12.18 9.8 10.08 9.85 9.07 8.57 8.92 10.05 4.41;

Data _null_;
array psi_tol (&no_mdl) (0.05 0.01 0.02);
array mdl_desc(&no_mdl) $32. ("Momey Market "
"Demand Deposit Account "
"Direct Deposit ");
do i = 1 to &no_mdl;
mdl_id = "dep" || put (i, z2.); /* required to have 0 before i */
call symput('mdl_desc' || put (i, z1.), mdl_id || " - " ||trim(left(mdl_desc(i))));
call symput('psi_tol' || put (i, z1.), trim(left(psi_tol(i))));
call symput('scr_var' || put (i, z1.), "scr_mdl_dep" || put (i, z2.) || "_NO");
call symput('rank_var'|| put (i, z1.), "rnk_mdl_dep" || put (i, z2.) || "_NO");
end;
run;

Page 11 of 16
%let scr_dsn = workdir.mdl_dep_scr;
%calc_psi_loop; /* PSI calculation */

PROC SQL VS. DATA STEP


The Structured Query Language (SQL) is a standardized, widely used database language to retrieve and update data in
relational tables and databases. PROC SQL is the SQL implementation within the SAS System. PROC SQL is a powerful
Base SAS procedure that combines the functionality of DATA and PROC steps into a single step. PROC SQL is part of Base
SAS software. Often, PROC SQL can be an alternative to other SAS procedures or the DATA step. The SQL code can be
embedded into SAS code via PROC SQL which would treat the SAS dataset as a relational table and perform most of the
functionality from SQL.

The RDBMS (Relational Database Management System) tables are tables like DB2/Teradata/Oracle tables that were created
with other software vendors' database management systems. PROC SQL can connect to, update, and modify RDBMS tables
with extra efforts to establish the connection and password authentication. A PROC SQL table is the same as a SAS data file.
It is a SAS file of type DATA. PROC SQL tables consist of rows and columns. The rows correspond to observations in SAS
data files, and the columns correspond to variables.

ETL stands for Extract, Transform and Load. Extract does the process of reading data from a table/database. Transform does
the process of converting of data into a format that could be appropriate for reporting and analysis. Load does the process of
writing the data into the target table/database. ETL is an important component of data warehouse architecture. The ETL
concepts can apply to PROC SQL and DATA step. The grid below shows that the combination of a SAS dataset and a
RDBMS table would be loaded via DATA step or PROC SQL. For example, the DATA step or PROC SQL can read a SAS
dataset and load it into a database table. Or read a database table and save it to a SAS dataset. DATA step can read/write
non-relational external data sources like EBCDIC flat files, VSAM files, spreadsheets, or ASCII files. PROC SQL cannot
handle these files.

Input Output
SAS dataset/table SAS dataset/table
SAS dataset/table RDBMS table
RDBMS table SAS dataset/table
RDBMS table RDBMS table

PROC SQL can perform summation, grouping, sorting, and row selection that are provided by the DATA step and the PRINT,
SORT, and SUMMARY procedures. PROC SQL can achieve the same results as Base SAS software but often with fewer and
shorter statements. SQL takes of the procedural details of getting results and printing the results without the SORT or PRINT
procedure. DATA step is procedural and processes one record at a time. The programmer needs to tell the DATA step how
to do to get results. PROC SQL is non-procedural and the programmer tells SQL what to do but not how to do it. In Example
2, the SQL aggregated function SUM is used to calculate the PSI and assign the value to a macro variable. It demonstrates
the simplicity of the code and the power of SQL. PROC SQL appears to be the most efficient method (both in terms of CPU
and real time) of accessing tables. PROC SQL often uses fewer resources than conventional DATA and PROC steps.

The SELECT statement


The SELECT statement is the primary tool of PROC SQL to identify, retrieve, and manipulate columns of data from a table. A
SELECT statement is also called a query because it queries or retrieves information from a SAS/RDBMS table. Several
optional clauses within the SELECT statement will place restrictions on a query. The SELECT statement contains the clauses
below. The SELECT statement must contain a SELECT clause and a FROM clause. When specifying clauses in a SELECT
statement, follow the following order:

1. The SELECT clause lists column(s) required to retrieve data. An asterisk on the SELECT statement will select all columns
from a table.
2. The INTO clause assigns values produced by PROS SQL to macro variables.
3. The FROM clause specifies the table name.
4. The WHERE clause specifies a condition that each row of the table must satisfy for query result.
5. The GROUP BY clause breaks a query result into subsets of rows. It is required when an aggregate function is used in
the SELECT clause.
6. The HAVING clause works with the GROUP BY clause to restrict the groups in a query result based on a given condition.
7. The ORDER BY clause sorts the output from a table by one or more columns.

Syntax of a SELECT statement:

PROC SQL options;


SELECT column(s)
Page 12 of 16
FROM table-name
INTO : macro variable(s)
WHERE expression
GROUP BY column(s)
HAVING expression
ORDER BY column(s);
QUIT;

PROC SQL executes without using the RUN statement. Use the QUIT statement to terminate the procedure.

PROC SQL Options


The followings are part of PROC SQL options:

 The NOPRINT prevents the SELECT statement from displaying its result table in SAS output.
 The NONUMBER prevents the SELECT statement from displaying the row number in the result table.
 The INOBS= and OUTOBS= restrict row processing.
 The NOEXEC checks SQL syntax without running the SQL.
 The FEEDBACK expands SELECT *. The log file will show columns to be selected.
 The STIMER times PROC SQL. The log file will show the CPU time for query.
The NOEXEC option and the VALIDATE SQL statement check the syntax of a query for correctness without submitting it to
PROC SQL. PROC SQL displays a message in the log file to indicate whether the syntax is correct.
The following two examples check the correctness of SELECT statement without execution.

proc sql;
validate
select * from workdir.mdl_dep_scr;
quit;

proc sql noexec;


select * from workdir.mdl_dep_scr;
quit;

With INOBS = 3, the following example will process 3 records only. The FEEDBACK option displays the columns that are
represented by a SELECT * statement. The STIMER option records and displays query execution time. The NUMBER option
displays the row number in the result table.

proc sql feedback inobs = 3 number stimer;


select * from workdir.mdl_dep_scr;
quit;

The log file shows the following message:

363 select * from workdir.mdl_dep_scr;


NOTE: Statement transforms to:

select MDL_DEP_SCR.acct_no, MDL_DEP_SCR.scr_mdl_dep_no, MDL_DEP_SCR.rnk_mdl_dep_no


from WORKDIR.MDL_DEP_SCR;

WARNING: Only 3 records were read from WORKDIR.MDL_DEP_SCR due to INOBS= option.
NOTE: SQL Statement used (Total process time):
real time 0.00 seconds
user cpu time 0.01 seconds
system cpu time 0.00 seconds
memory 272.87k

…………………
…………………

The query results will show in the list file:


Row PROD_ACCT_NO scr_mdl_dep_no rnk_mdl_dep_no
----------------------------------------------------------- ----------------------------
1 69 476.64 5
2 83 2706.95 1

Page 13 of 16
3 115 1675.92 1

The options after PROC SQL would change or reset options. The RESET statement can also be used to add, drop, or change
the options in the PROC SQL statement. The NOPRINT option prevents the SELECT statement from displaying its result table
in SAS output. The example below first uses the NOPRINT option. Then use RESET statement to changes the NOPRINT
option to PRINT and adds the NUMBER option, which displays the row number in the result table.

proc sql noptint;


select * from workdir.mdl_dep_scr;

reset print number;


proc sql;
select * from workdir.mdl_dep_scr;
quit;

USE THE SQL TO CREATE MACRO VARIABLE(S)


SQL provides the INTO clause in the SELECT statement for creating SAS macro variables. The INTO clause for the SELECT
statement can assign the result of a calculation or the value of a data column (variable) to a macro variable. The INTO clause
follows the same scoping rules as the %LET statement. In PROC SQL, the SELECT clause is used with INTO to place the run
time values of one or more of the SAS variables (columns) into one or more macro variables. The selected variables from the
table are placed into the corresponding macro variables, each macro variable must be preceded by a colon (:) and be
separated by a comma.

The following examples will demonstrate different methods to create macro variable(s) via PROC SQL:
1. Store column values in declared macro variables
2. Store values of all rows in one macro variable
3. Store row values in a list of macro variables

Method 2 and 3 will be used to create a macro pseudo-array. The scored dataset mdl_dep_scr with rank variable as
rnk_mdl_dep_no and rank value from 1 to 10 will be used in the following examples.

Example Q1: Store Column Values in Declared Macro Variables


The general syntax of storing column values in declared macro variables is:

PROC SQL NOPRINT;


SELECT <var1>, <var2>
INTO :<mvar1>, :<mvar2>
FROM < table>;
QUIT;

The following example stores the maximum score into the macro variables max_scr_val and stores the minimum rank into the
macro variable min_rank_val:

proc sql noprint;


select max(scr_mdl_dep_no), min(rnk_mdl_dep_no)
into :max_scr_val, :min_rank_val
from workdir.mdl_dep_scr;
%put max_scr_val = &max_scr_val min_rank_val= &min_rank_val ;
quit;

The following example uses GROUP BY and HAVING class. The total count of rnk_mdl_dep_no = 5 will store in the macro
variable rnk_cnt_eq_5.

proc sql noprint;


select count(*) into :rnk_cnt_eq_5 from workdir.mdl_dep_scr
group by rnk_mdl_dep_no
having rnk_mdl_dep_no = 5 ;
%put rnk_cnt_eq_5 = &rnk_cnt_eq_5 ;
quit;

Example Q2: Create a Macro Variable with a List Of Values


The SQL can concatenate the values of one column into one macro variable to build up a list of values separated by a
character. The macro variable rank_val will be populated with 10 rank values ‘1 2 3 4 5 6 7 8 9 10’. The SEPARATED BY
'character' specifies a character that separates the values of the rows. The separator could be a space, a comma or any other
Page 14 of 16
character. The SYMGET is one of DATA step functions to interface with macro facility and it returns the value of a macro
variable to the DATA step during DATA step execution. The SYMGET(‘rank_val’) will be used to retrieve the value of the
macro variable in PROC SQL.
proc sql;
select distinct rnk_mdl_dep_no into :rank_val separated by ' ' from workdir.mdl_dep_scr;
%put rank_val= &rank_val ;
quit;

Example Q3: Create A Macro Pseudo-Array


The following example returns the row values into a range of macro variables. The :rank_val1 - :rank_val999 is specified in the
example with maximum 999 values can be stored. The SAS Macro Facility creates only the number of macro variables that
are needed. Since the rnk_mdl_dep has 10 ranks, only :rank_val1 - :rank_val10 is created. The automatic macro variable
SQLOBS contains the number of rows that are processed by a SQL procedure statement. If a macro variable list or macro
variable range is created, then SQLOBS contains the number of rows that are processed to create the macro variable list or
range. The SQLOBS would return the value of 10 for Example Q2 and Q3.

proc sql;
select distinct rnk_mdl_dep_no into :rank_val1 - :rank_val999 from workdir.mdl_dep_scr;
%put sqlobs= &sqlobs;
quit;

When specifying the upper bound for a range of macro variables, make sure that the number is large enough. If it is too small,
some values return from rows will be lost and there is no error or warning message. In the following code, the &rank_val4 is
undefined.

proc sql;
select distinct rnk_mdl_dep_no into :rank_val1 - :rank_val3 from workdir.mdl_dep_scr;
%put sqlobs= &sqlobs;
quit;

Example Q4: Use a Hyphen Clause to Specify a Range without an Upper Bound
The following example would not specify an upper bound. The SQLOBS automatic variable is useful to pass how many
variables were actually created for a subsequent need. The macro variable :rank_val1 - :rank_val10 will be created from the
code below.
proc sql;
select distinct rnk_mdl_dep_no into :rank_val- from workdir.mdl_dep_scr;
quit;

Please do specify an upper bound when using a SQL aggregated function. The following code is supposedly using the SQL
COUNT function to get the count of each rank for the column rnk_mdl_dep. Without specifying an upper bound for rank_cnt,
the result is unexpected.
proc sql;
select count(*) into :rank_cnt- from workdir.mdl_dep_scr group by rnk_mdl_dep_no;
quit;

The log file has the warning message:


WARNING: INTO Clause :count through : does not specify a valid sequence of macro variables.

The code below will assign the count to a range of macro variables :rank_cnt1 - : rank_cnt10 and assign the rank to
:rank_val1 - :rank_val10.

proc sql;
select count(*),rnk_mdl_dep_no into :rank_cnt1 - : rank_cnt10 , :rank_val1 - :rank_val10
from workdir.mdl_dep_scr
group by rnk_mdl_dep_no;
quit;

SUMMARY
The SAS macro facility is extremely useful/powerful to enhance and extend the functionality of the SAS System. The paper
demonstrates how to substitute macro variables to create dynamic code and use a macro variable with a list of values and
macro pseudo-array to perform iterative %DO. The paper also provides practical examples/tips/techniques which can be
applied to variety of applications with some changes.
Page 15 of 16
The SAS macro does have many benefits. However, overusing macro would add unnecessary complicity of code and make
the code not easy to maintain.

Incorporating macro code into a SAS application does not automatically make the application more efficient. Use macro
techniques only when it is necessary and balance resource savings with maintainability and ease of use.

REFERENCES
Advanced Macro Topics by Steven First, Systems Seminar Consultants, Madison, WI (SUGI27, 2002)
DATA Step vs. PROC SQL: What’s a neophyte to do? by Craig Dickstein, Ray Pass (SUGI29 – 2004)
Macros Invocation Hierarchy: Session Compiled, Autocall, and Compiled Stored Macros by Susan M. O'Connor
SAS® 9.4 SQL Procedure User's Guide, Second Edition, July 2015
SAS® 9.4 Macro Language: Reference, Fourth Edition, July 2015
SAS® 9.4 Language Reference Concept, Fifth Edition, July 2015

CONTACT INFORMATION
Your comments and questions are valued and encouraged. Contact the author at:
Sophia Yue
Bank of America
1825 E Buckeye Rd
Phoenix AZ 85034
Work Phone: (602) 464-2317
Email: sophia.s.yue@bankofamerica.com
Web: www.bankofamerica.com

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.

Page 16 of 16

Vous aimerez peut-être aussi