When you say dynamic programming in SAS, most programmers think of the macro language. However, sometimes it is not the appropriate tool. If you want to write data-driven code, you should familiarize yourself with the CALL Execute Routine. This post serves as an introduction to Call Execute logic and how to use it to your advantage. I will demonstrate a few examples of how to use it as well.
The SAS Call Execute Routine
The Call Execute Routine accepts a single argument. Either as a hardcoded string, a data step character variable, or a macro variable, that resolves to a character expression. Furthermore, the argument can be any concatenation of them. SAS evaluates the expression in the data step and pushes the resulting code back into an input stack for later execution. Consequently, Call Execute builds the code as the data step iterates, and pushes the code into an input stack, that executes after the data step terminates. This is very important to understand, so I will repeat it: The resulting code is executed after the data step that builds the code terminates. Unless we serve macro statements to the Call Execute Routine. The Call Execute sends macro code to the macro processor where it executes immediately. Meanwhile, the data step execution pauses.
A Simple Call Execute Example
Let us look at a simple example of how to use the Call Execute Routine. In the code below, I have three statements. Each of then contains a character string with a simple SAS expression. When each expression is processed, the code is pushed into a queue, that executes after the data step terminates. First-in first-out (FIFO). SAS issues a note in the log and shows the code that the routine generates.
After the data step terminates, the generated code executes. In this case, it simply executes a data step to create a copy of the Sashelp.Class data step.
data callstack; call execute("data class;"); call execute("set sashelp.class;"); call execute("run;"); run;
Now let us take this a bit further. In the code above, I simply hard code SAS code into the Routine. Let us utilize the dynamic nature of the Routine. First, I create the data set ds with three observations. Next, I use the data step and set the ds data set. Then I use the Call Execute Routine to create a data set for each observation in ds. I use the Cat Function to concatenate the character expressions, which now consist of both hardcoded text and the name variable from ds. Furthermore, I use the Compbl Function to ensure that the code looks nice when we present it in the log. In the first iteration, the name variable resolves to “one”. In the second iteration, it resolves to “Two” and so on.
data ds; input name $; datalines; one two three ; data _null_; set ds; call execute (compbl(cat( "data ", name, "; set sashelp.class; run;" ))); run;
As you can see in the log, the code that is pushed to the queue is equivalent to the code below.
data one; set sashelp.class; run; data two; set sashelp.class; run; data three; set sashelp.class; run;
Lastly, let me mention that in the above explanations, I do simplify things a little. Because I assume that the argument passed to the Call Execute Routine does not contain macro code. If it does, then things get a little more complicated. And suddenly, it even matters whether the macro variables are enclosed in single or double quotation marks. You can read more about those situations in the blog post CALL EXECUTE made easy for SAS data-driven programming.
In this post, I introduce the Call Execute Routine and present how to utilize it with a few examples. I briefly introduce how the Routine works and when the code is assembled and executed. Furthermore, I present a few examples. I have used the Call Execute routine quite a few times before. Especially, in posts about performance, where I do several runs of the same code with varying parameters. You can see a few of them below in A SAS Case Study of the BUFSIZE and BUFNO Options and Understand the Dosubl Function in SAS.
You can download the entire code from this post here.