1

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 ! :)

Vincent
  • 955
  • 2
  • 15
  • 32
  • Here's a link a previous question on how to rename variables http://stackoverflow.com/questions/26855371/subsetting-a-dataset-by-selecting-variables-based-on-keywords-in-their-name-in-s/26855951#26855951 – Reeza Dec 09 '14 at 23:36

2 Answers2

2

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:

  1. 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

  2. Now %prog2 - here's only macro statement %PUT which puts (still empty) &mv1 variable. That what you see in the log
  3. Now all the what gets executed immediately has been done. The data step which contains call execute ends.
  4. 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

vasja
  • 4,732
  • 13
  • 15
  • Thanks, I understand better now. However, I can't remove the `call symputx`equivalent in my original code. Is there a command you would suggest to replace `call execute` ? – Vincent Dec 09 '14 at 11:57
  • Depends on why do you need call execute? Is the macro call dynamic? Is there some sequence of calls? – vasja Dec 09 '14 at 12:04
  • I edited my question to explain what I'm trying to do. – Vincent Dec 09 '14 at 12:18
  • In fact I use the exact same way as the one suggested by your new link ! But the macrovariable is defined with a `proc sql` so it's the same as the `call symputx` in my example. – Vincent Dec 10 '14 at 08:32
0
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.

FriedEgg
  • 201
  • 1
  • 3