4.1 Flow control

A huge part of programming (in any language) is the use of so called "conditional statements". We do this in SAS using "if" statements. The following code creates a new variable "age_group" which is "young" if the age is less than 29 and "old" if the age is larger than 29. Note we're also including a keep statement to just have the name and age_group in the new data set.

data age_group(keep= name age_group);
set mat013.mmmjjj;
if age<30 then age_group='young';
    else age_group='old';
run;

We can also use this in conjunction with the else if statement as shown below:

data age_group(keep= name age_group);
set mat013.mmmjjj;
if age<18 then age_group='child';
    else if age<30 then age_group='young';
        else age_group='old';
run;

Note that we can also compare strings as shown with the following code:

data age_group(keep= name age_group);
set mat013.mmmjjj;
if age<18 then age_group='child';
    else if age<30 then age_group='young';
        else age_group='old';
if substr(Name,1,1)='J ' then data_set='JJJ';
    else data_set='MMM';
run;

Here are some of the comparison operators that can be used in conjunction with 'if' statements.


A further important notion in programming is the notion of loops. These are done in SAS using "do" statements. There are four ways the "do" statement is used:

  1. do
  2. do (iterative)
  3. do while
  4. do until

The first use allows us to combine several statement into one. This is often used in conjunction with "if" statements:

data age_group(keep= name age_group minor_Y_N);
set mat013.mmmjjj;
if age<18 then do;
age_group='Child';
minor_Y_N='Y';
end;
else do;
age_group='Adult';
minor_Y_N='N';
end;
run;

The 'do' statement can be used to push your computer a bit more. The "do iterative statement" allows you to automate various procedures. The following code output the total number of birthday candles that would have been used on everyones birthday cake in the JJJ data set.

data candles(keep= name age candles);
set mat013.jjj;
candle=0;
do k=0 to age;
candle=candle+k;
end;
run;

The last two uses of the 'do' statement are very similar and allow us to iterate "until/while" a particular condition is met.

The do until (expression) statement executes a group of statements until the expression within the brackets is satisfied. The validity of the expression is checked at the end of each loop.

do until (expression);
data step commands;
end;

The following code outputs the number of even numbers less than or equal to 70, computing each even number and checking whether or not it is more than 70.

data even_numbers;
k=0;
even=0;
do until(even>=70);
even=2**k;
k=k+1;
end;
run;

We can do a similar calculation using the do "while" statement. The do while (expression) statement executes a group of statements whilst the expression within the brackets is satisfied. The validity of the expression is checked at the beginning of each loop.

do while (expression);
data step commands;
end;

data even_numbers;
k=0;
even=0;
do while(even<70);
even=2**k;
k=k+1;
end;
run;

Note that do iterative statements (also called "do loops") are often used in conjunction with the "output" statement which empties the pdv to the output data set. The following code outputs the variables in the pdv: "k" and "even" at each iteration of the do statement. The output is shown.

data even_numbers;
k=0;
even=0;
do while(even<70);
even=2**k;
output;
k=k+1;
end;
run;


4.2 How does SAS compile code?

In this chapter we will see how to program macros in SAS. Macros generate and run code with varying arguments. The macro facility is a tool for extending and customising SAS and for reducing the amount of text you must enter to do common tasks. The macro facility enables you to assign a name to character strings or groups of SAS programming statements. From that point on, you can work with the names rather than with the text itself.

When you submit a SAS macro the Input stack receives content of the program. Word scanner scans each line of the macro for tokens. If a token contains a macro character (a % or a &) that token is sent to the macro compiler. The Macro compiler does its work and places tokens back in the input stack. The token is examined by the word scanner and the process repeats. When the word scanner detects a step boundary it triggers the data step compiler. This process is represented diagrammatically.


When you submit a macro, it goes first to the macro processor which produces standard SAS code from the macro references (macro code is compiled first). Then SAS compiles and executes your program.

In general the syntax for a macro is as follows:

%macro macro-name <(macro-parameter-list>;

… SAS Code...

%mend <macro-name>;

The following example creates a macro called "My_plot" which when called will plot a graph of height against weight of the variables in mat013.jjj:

%macro My_plot;
proc gplot data=mat013.jjj;
plot height_in_metres*weight_in_kg;
run;
%mend;

To run the macro we call it with the following statement:

%My_plot;

As discussed above, it is possible to pass arguments to a macro. The following code creates a macro "shopping" that will remove a certain quantity "spend" from the variable "life_savings":

%macro shopping(spend);
data JJJ_after_shopping(keep= Name Old_savings New_savings);
set mat013.jjj;
Old_savings=savings_in_pounds;
New_savings=saving_in_pounds-&spend;
run;
%mend;

Note the ampersand "&" which the "word scanner" will recognise, sending "&spend" to the "macro compiler" where it will resolve to whatever value is passed to the macro.

We can define macros with multiple variables. Consider the following modification of the above code which allows for multiple shopping trips:

%macro shopping(spend,trips);
data JJJ_after_shopping(keep= Name Old_savings New_savings);
set mat013.jjj;
Old_savings=savings_in_pounds;
New_savings=saving_in_pounds-&trips*&spend;
run;
%mend;

The above code is using so called "positional" macro parameters. It is possible to also use "keyword" macro parameters as shown in the code below.

%macro shopping(spend=,trips=);
data JJJ_after_shopping(keep= Name Old_savings New_savings);
set mat013.jjj;
Old_savings=savings_in_pounds;
New_savings=saving_in_pounds-&trips*&spend;
run;
%mend;

We can then call the above macro and change the order of the parameters:

%shopping(trips=2,spend=500);

It's also possible to set default values:

%macro shopping(spend=,trips=1);
data JJJ_after_shopping(keep= Name Old_savings New_savings);
set mat013.jjj;
Old_savings=savings_in_pounds;
New_savings=saving_in_pounds-&trips*&spend;
run;
%mend;

Now if we call the macro without giving a value to trips it will take the default value 1.

%shopping(spend=500);

4.2.1 Macro variables

In this section we're going to take a slightly closer look at macro variables. A macro variable is a variable whose value is stored within the macro symbol table. When the macro variable is used in SAS code, SAS substitutes the value of the macro variable into the SAS code. SAS macro variables are distinguished by the "&" sign before the variable name. Note that all SAS macro variables are stored as text strings.

We can experiment with macro variables using the %let statement which allows the construction of macro variables outside of a macro definition. This is the simplest form of a macro statement. It can be placed anywhere in a program, not only inside a Macro. "%let" creates global macro variables. An example of this is shown in the following code which gives the output shown.

%let spend=400;
%let trips=500;

%macro shopping;
data JJJ_after_shopping(keep= Name Old_savings New_savings);
set mat013.jjj;
Old_savings=savings_in_pounds;
New_savings=saving_in_pounds-&trips*&spend;
run;
%mend;

%shopping;


It's also possible to view (in the log) the values of a macro variable using the "%put" statement. There are two uses for it:

%put <text> &macro-variable-name;

This outputs some (optional) followed by the value of particular macro variable. The other use is shown below:

%put  <_all_ | _global_ | _local_ >;

This will output either all, all the global or all the local macro variables. These statements should allow us to better understand some of the issues related to the resolution of multiple ampersands. Multiple ampersands can be used to allow the value of a macro variable to become another macro variable reference. The macro variable reference will be rescanned until the macro variable is resolved. There are 2 rules to follow:

  1. && is a token in its own right and resolves to &
  2. Each token is handled independently

The important thing to note here is that a double ampersand "&&" is a token in itself that resolves to a single ampersand "&" (THIS IS IMPORTANT).



4.3 SAS Macro programming statements

The 'if' statements and 'do' loops discussed previously work in a very similar way to if statements and do loops within macros. The only modification is that these can be evaluated within the macro compiler before the entire submitted code is resolved. For this to work we need to use the "%if", "%then" and "%else" statements when evaluating a conditional statement on a macro variable. The following code is an example of this:

%macro shopping(spend,trips);
data JJJ_after_shopping(keep= Name Old_savings New_savings);
set mat013.jjj;
%if &spend<0 %then %put Carefull the spend is negative!;
%else %put The spend is positive;
Old_savings=savings_in_pounds;
New_savings=savings_in_pounds-&trips*&spend;
run;
%mend;

The "%do" statement can be used in conjunction with "%if" statements. The following code creates one of two data sets depending on the sign of the macro variable spend.

%macro shopping(spend,trips);
%if &spend<0 %then %do;
data JJJ_after_saving(keep= Name Old_savings New_savings);
set mat013.jjj;
%end;
%else %do;

data JJJ_after_spending(keep= Name Old_savings New_savings);
set mat013.jjj;
%end;

Old_savings=savings_in_pounds;
New_savings=savings_in_pounds-&trips*&spend;
run;

%mend;

Another use of the %do statement is in iterative statements (as before). The difference being that on this occasion the %do statement creates macro variables. The following code creates various data sets each with a title indexed by a macro variable.

%macro shopping(spend);
%do trips=1 %to 10;

data JJJ_after_saving_&trips(keep= Name Old_savings New_savings);

set mat013.jjj;

Old_savings=savings_in_pounds;
New_savings=savings_in_pounds-&trips*&spend;

run;
%end;
%mend;

The %do statement can also be used in conjunction with the %while and %until statements.

The way SAS compiles macro code can be an extremely useful tool. For example the following code creates a macro that imports 5 separate csv file:

%macro import;
%do i=1 %to 5;
proc import datafile="\~/File_&i.csv"
    out=File_&i
    dbms=csv
    replace;
    getnames=yes;
run;
%end;
%mend;

The output is shown.


4.4 Macro functions

Since all macro variables are text strings it is not possible to directly perform computations on macro variables that contain numbers. The following code would give an error:

%let var=5**2;

%put &var;

One must make use of the following function to be able to evaluate (in the macro compiler) such computations:

%let var=5**2;

%put %eval(&var);

%put %sysevalf(&var);

The "%sysevalf" function works in a very similar way to the "%eval" but will compute fractions such as 9/2 in the Real numbers (as opposed to eval which would round the result).

Another use of macro functions is when it comes to ignoring certain SAS keywords. The following code puts two different statements to the log.

%let myvar=abc;
%put %str(this string is; &myvar);
%put %nrstr(this string is; &myvar %let);

The first macro function "%str" ignores the ";" and treats it as a string. The second macro function "nrstr" ignores all the SAS statements including ";,&" and "%".

There are a large number of macro functions and it's worth looking around if you think there's one you might need. Also, of interest are the following commands (look them up) that can help with debugging:

  1. mprint
  • writes all non-macro code generated by the macro
  1. mlogic
  • when a macro begins executing
  • values of macro parameters
  • when program statements execute
  • the status of any %if or %do condition
  • when a macro stops executing
  1. Symbolgen
  • writes information concerning the resolution of macro variables to the log