macro references execution in call execute - sas

SAS documentation says the macro references in call execute are executed immediately. Does this code exemplify it?
%let var = abc;
data _null_;
call execute ('&var');
run;

Sort of. Here is a more complete example using value of the macro variable that is actual executable SAS code.
data _null_;
call symputx('var','data;run;');
run;
%put var= %superq(var);
data _null_;
call execute ('&var');
run;
You can see in the SAS log that the code that CALL EXECUTE() actually pushed onto the stack to run is the VALUE of the macro variable even though the single quotes would prevent the macro variable from expanding during the data _null_ step that is using the CALL EXECUTE() statement.
NOTE: CALL EXECUTE generated line.
1 + data;run;

Related

What will be the output of this %macro function in SAS and how to display the output in sas studio

%macro segm1;
data _null_;
%do i=0 %to 8;
call symput("yyyymm_i",put(intnx('month',today(),-1,'b'),yymmn6.));
%end;
%mend;
%segm1;
run;
What will be the output and how to get/dispaly/view output of this macro code in sas studio?
Since a macro is used to generate SAS code to view the output of macro set the MPRINT option before running it. You will see that the macro generates a data statement and 8 call symput statements.
There are a lot of problems with that code.
Uses %DO loop where it should be using a DO loop.
Creates the same macro variable over and over.
Starts a data step, but does not end it. Was this on purpose? Why?
Creates LOCAL macro variables that will disappear when the macro finishes.
Uses older less functional call symput() function instead of call symputx().
If you want to create 8 macro variables just use a normal DO loop. No need for a macro. Use the value of the loop variable to change the name of the macro variable generated and the month the result represents.
data _null_;
do i=0 to 8;
call symputx(cats('yyyymm_',i),put(intnx('month',today(),-i,'b'),yymmn6.));
end;
run;
Which will create a series of macro variables named YYYYMM_0 to YYYYMM_8 with six digit strings like 202204 , 202203 , ... representing the current month back to eight months ago
If you did want to run that inside a macro and have the macro variables it creates available after the macro ends then set the optional third parameter to call symputx() to the string 'G' so that they are defined in the global symbol table instead of the local symbol table.
You can print individual macro variables to the log with the %put statement, like %put &yyyymm_i;
You can print all macro variable with %put _all_;, or if you are only interested in variables you created yourself: %put _user_; (or within a macro %put _local_;)
By the way, your code is wrong, try this
%macro segm1;
data _null_;
%do i=0 %to 8;
call symput("yyyymm_&i", put(intnx('month',today(),-1,'b'),yymmn6.));
%end;
%mend;
%segm1;
run;
%put _user_;

How is do loop working in this code ? Why call execute is working without loop ending?

Need to understand why call execute is working when it is outside the loop for each iteration ?Variable name will be overwritten every time so I should get result for last variable in my dataset rather that all 111 variables.
data _null_;
set basel.Data_Dictionary;
do i =1 to 111 ;
call symput('Varname',NAME);
%put &varname.;
end;
call execute ('%missimp(&varname.)');
run;
Not sure what you mean by outside the loop?
The first thing that program will do is print the value that the macro variable VARNAME has BEFORE the data _null_ step starts to the log. Note that macro code is processed first and then the resulting text is interpreted as the SAS code that you want to run. It would be less confusing to place the %put statement before the data statement.
Your datastep will "loop" over each observation in your source dataset. It will read an observation from your input data. The DO loop will cause it to set the macro variable VARNAME to the same value one hundred and eleven times. Then it will place a call to the macro named MISSIMP that will use the value of VARNAME (at the time the CALL EXECUTE statement ran). This will repeat until the SET statement tries to read past the end of input dataset. All of those macro calls will run after the current data step finishes.
A much simpler process would be just skip the CALL SYMPUT statement and use the value of NAME to generate the code to pass to CALL EXECUTE. Like this:
data _null_;
set basel.Data_Dictionary;
call execute(cats('%missimp(',NAME,')'));
run;

Calling a macro several times

I have a pretty large macro that I want to call several times. (I'm using replicate weights to calculate my error.) I want to call the process for different variables, say VAR1-VAR99. In the past I've used a DATA NULL step and CALL EXECUTE like so:
data _null_;
do i=1 to 99;
call execute(compress("%mymacro(VAR" || i || ")") );
end;
run;
This isn't working for me this time, though. There might be something I'm missing about the scope of macro variables? I'd like to call:
%mymacro(VAR1)
%mymacro(VAR2)
...
%mymacro(VAR99)
and of course I'd like to do this without 99 lines of code. Why might my method be suddenly failing me? What are other ways to do this?
Here is an example of generating macro calls with call execute. I added %NRSTR, as it prevents macro timing issues. It makes the call execute generate the macro call, without actually executing the macro. If your macro generates macro variables from data, without the %NRSTR you can end up with timing issues and scope issues.
%macro mymacro(var) ;
%put var=&var ;
%mend mymacro ;
data _null_;
do i=1 to 5;
call execute(cats('%nrstr(%mymacro(var',i,"))")) ;
end;
run;
Or it could be as simple as changing your code to use single quotes instead of double quotes. Single quotes will prevent the macro from executing when the data step compiles. If your macro does not generate macro variables from data, this may be enough. But I always use %NRSTR.
data _null_;
do i=1 to 5;
call execute(compress('%mymacro(VAR' || i || ")") );
end;
run;
Don't use call execute, try to call macro program in macro program.
%macro repeat(n);
%do i=1 %to &n;
%mymacro(VAR&i);
%end;
%mend;
Large is probably the key word in that question. Let me explain.
You are pushing the macro calls onto the stack using call execute(). But what actually is getting placed on the stack is the code generated by the macro and not the call. Look at the lines with + at the beginning in the SAS log.
If the macro generates just a few lines of code then not much is stacked up to run after the data step. But if it is large then you might overload the stack.
Also if the macro uses the lines of SAS code it generates to create macro variables (using call symputx() or SQL's into clause) that later drive the macro's logic there will be a timing issue. Again that is more likely to happen with a large macro than a small (simple) macro.
Wrap the macro call (or at least the macro's name) in %nrstr() will prevent SAS from running the macro during the call exucute() call. Instead the macro call will placed onto the stack to be run after the data step finishes.
Consider this simple macro definition.
%macro mymacro(varname);
proc means data=sashelp.class ;
var &varname ;
run;
%mend mymacro;
If I use call execute() to generate calls to it like this:
data _null_;
call execute('%mymacro(age)');
call execute('%mymacro(height)');
call execute('%mymacro(weight)');
run;
Then you will see lines like this in the SAS log
1 + proc means data=sashelp.class ; var age ; run;
2 + proc means data=sashelp.class ; var height ; run;
3 + proc means data=sashelp.class ; var weight ; run;
But if instead you add %nrstr() like this:
data _null_;
call execute('%nrstr(%mymacro)(age)');
call execute('%nrstr(%mymacro)(height)');
call execute('%nrstr(%mymacro)(weight)');
run;
Then the lines in the SAS log look like this.
1 + %mymacro(age)
2 + %mymacro(height)
3 + %mymacro(weight)

SAS execute macro conditionally

I want to execute a macro conditionally, based on some loop variable in the dataset.
data alldat;
do i=1 to 5;
* here, a macro should be called ;
* that is accessing some array variable of the dataset ;
* e.g. %my_macro(my_array(i));
%put hello;
output;
end;
run;
proc print; run;
How is this possible?
If I execute this example code above, hello is only output once, while alldat contains 5 values, as one would expect. I want 5 hellos in my output.
Thank you!
If you want your data step loop to output hello 5 times then use a PUT statement instead of a %PUT statement.
In general macros are used to generate SAS code that is then executed. It really depends on what type of code your macro generates. If it only generates statements than can be used inside of a data step then call it once inside of your DO loop and the generated statements will run 5 times. So if your macro generates data step statements that could update the variable whose name is passed to it then your code might look like this.
data alldata;
array my_array var1-var5 ;
do i=1 to dim(my_array);
%my_macro(my_array(i));
put 'hello';
output;
end;
run;
Otherwise you could use CALL EXECUTE to generate the macro calls so that they can then run and generate their code after the data step stops. This data step will read values from an existing array and pass the values to the macro. So it will generate 5 calls to the macro for every observation in the input data. The generated macro calls will run after the data step stops.
data _null_;
set mydata;
array my_array var1-var5 ;
do i=1 to dim(my_array);
call execute(cats('%nrstr(%my_macro)(',my_array(i),');'));
call execute('%nrstr(%put hello;)');
end;
run;

Why does my macro behave differently with call execute()?

Using SAS, I often want to perform an action on each row of a dataset. To do so, I use a command I found on a tutorial : call execute(). As I'm not very familiar with SAS environment, I tend to use macro-functions to do anything I don't know how to and execute them with call execute().
However I have difficulties understanding how macro-language works exactly in SAS. I know that all macro references are resolved first, which provides a base-SAS code which is then executed (or am I already wrong ?). But I don't understand how it applies with call execute().
Let's consider the following code :
%macro prog1; /* %prog1 defines a macrovariable mv1 */
%global mv1;
data _null_;
call symputx("mv1","plop");
run;
%mend;
%macro prog2(var); /* prog2 puts it on the log */
%put PUT &var;
%mend;
%macro prog_glob; /* prog_glob executes prog 1 then prog2 */
%prog1;
%prog2(&mv1);
%mend;
I know there is no need for three macros here but this is a minimal version of my real code, which has this structure.
Now if I execute prog_glob :
%prog_glob;
I get PUT plop on the log, as expected.
But if I use it with call execute() (even if there is no need for loop here) :
data _null_;
mac=%NRSTR("%prog_glob");
call execute(mac);
run;
I get only PUT.
There is no error suggesting that the macrovariable is not defined so the %global statement worked. But somehow, prog2 was executed before prog1 base part (at least I think so) and mv1 is not defined yet.
My questions are :
Is my interpretation correct ?
Why does the result change when I use call execute ?
Depending on the precedent question answer, how should I fix it or is there a more convenient way to loop trough a column values ?
EDIT : My original code intends to rename the variables of several tables, which I have listed in a dataset. For each listed table, I want the following algorithm executed :
prog1 : store a list with all variables in a macrovariable (this is where I define mv equivalent)
prog2 : add a common suffix to these variables names
There is probably a more clever way to do this. Again, I'm not so familiar with SAS and I tend to over-use macros. If you want to show me a better way to do this, I'd be happy to chat but I don't expect you guys to rewrite all my code so an alternative to call execute would be enough for me to be grateful ! :)
Let's have a look at the documentation
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a000543697.htm
If an EXECUTE routine argument is a macro invocation or resolves to one, the macro executes immediately. However, any SAS statements produced by the EXECUTE routine do not execute until after the step boundary has been passed.
Note: Because macro references execute immediately and SAS statements do not execute until after a step boundary, you cannot use CALL EXECUTE to invoke a macro that contains references for macro variables that are created by CALL SYMPUT in that macro. See Interfaces with the Macro Facility, for an example.
This means, if you call it via call execute:
macro statements are executed immediately - those are:
1.1. first in %prog1: %global mv1; - so mv1 is defined but empty, no Apparent... warning
1.2. SAS statements from %prog1 are still deferred
Now %prog2 - here's only macro statement %PUT which puts (still empty) &mv1 variable. That what you see in the log
Now all the what gets executed immediately has been done. The data step which contains call execute ends.
SAS statements deferred from call execute are now being executed:
4.1. the dataset from prog1 sets the value for mv1.
And that's all :-)
EDIT: regarding your edit: try looking at this http://support.sas.com/kb/48/674.html
data _null_;
mac='%nrstr(%prog_glob)';
call execute(mac);
run;
or, more plainly, as you would see in the documentation...
data _null_;
call execute('%nrstr(%prog_glob)');
run;
or
%let prog=%nrstr(%prog_glob);
data _null_;
mac="&prog.";
call execute(mac);
run;
or, and I wouldn't really recommend this one, but you could also manually concatenate the macro quotes
data _null_;
mac=cats('01'x,'%prog_glob','02'x);
call execute(mac);
run;
The way you are running it, the macro statements get execute at run time and the data step is execute after the calling data step completes. You're not properly using %NRSTR for this context, as described by the documentation. You need to pass the macro, along with the quoting as text to the call routine.