DATA Step, Macro, Functions and more

call a macro inside call execute, and macro variables resolution

Accepted Solution Solved
Reply
Contributor
Posts: 43
Accepted Solution

call a macro inside call execute, and macro variables resolution

Hi,

please check out this code snippet which is driving me crazy:

data dataset;

  par = 1;

  var = 'Valore';

run;


%macro mmm(par1);

  %put macrovar1=&macrovar;


  proc sql;

  select var || put(time(),time10.) into :macrovar from dataset where par = &par1;

  quit;


  %put macrovar2=&macrovar;

%mend;


data _NULL_;

  call execute("%mmm(1)");

run;

I expect that macrovar1 puts "not resolved" and macrovar2 puts e.g. "Valore 15:00:00". Instead, I get "not resolved" either in macrovar1 and in macrovar2. Moreover, "macrovar" becomes oddly a global macro variable, hence if I execute again this snippet I get "Valore 15:00:00" either in macrovar1 and in macrovar2, which does not make any sense since I expect macrovar1 to be "not resolved" and macrovar2 to be "Valore 15:01:00" i.e. a new value instead of keeping the old value.

However, if I replace the last data step simply with %mmm(1); it works exactly as expected. So what is "call execute" doing wrong?

I hope I made myself clear.

Thanks a lot

Regards


Accepted Solutions
Solution
‎07-03-2015 06:26 AM
Super User
Posts: 6,936

Re: call a macro inside call execute, and macro variables resolution

The macro is executed when it is called during the compilation phase of the data _NULL_ step, but the proc sql runs after the text created by the macro is handed over to the SAS system when the data _NULL_ step has finished its execution phase. Therefore the macro reaches its %mend long before the sql ever runs.

You can watch this when you put

options mlogic mprint;

right before the data _null_ step.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers

View solution in original post


All Replies
Solution
‎07-03-2015 06:26 AM
Super User
Posts: 6,936

Re: call a macro inside call execute, and macro variables resolution

The macro is executed when it is called during the compilation phase of the data _NULL_ step, but the proc sql runs after the text created by the macro is handed over to the SAS system when the data _NULL_ step has finished its execution phase. Therefore the macro reaches its %mend long before the sql ever runs.

You can watch this when you put

options mlogic mprint;

right before the data _null_ step.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Super User
Super User
Posts: 7,401

Re: call a macro inside call execute, and macro variables resolution

To be honest, I don't see why you would want to be selecting data into a macro variable in code which is called by call execute.  The basic premise of using call execute is to generate code based on the output from a datastep.  So if i take a problem, say I want to print all 4 ABC variables, then I wouldn't call execute a macro which creates a list of of these variables, as I already have the datastep for such a thing:

data _null_;

     do i="ABC1","ABC2","ABC3","ABC4";

          call execute('%print_macro (var='||strip(i)||');');

     end;

run;

as KurtBremser has stated, you are trying to generate code (via the pre-processor) at two separate stages which doesn't make sense.  Get the information you would put in macro variables into a dataset - remembering that you can do pretty much anything here, distinct lists for loops, do, calculations etc. then use that input dataset as the driver for call execute to generate the code from.

Contributor
Posts: 43

Re: call a macro inside call execute, and macro variables resolution

Thank you very very much, I understand, I'll change the code as you suggest.

So two last questions:

  • why that code made macrovar global? just curious
  • is there a function to resolve a macrovariable at execution-time without using neither a datastep nor a proc?
Super User
Posts: 6,936

Re: call a macro inside call execute, and macro variables resolution

Since the SQL runs after the data _null_ step and therefore outside of the macro, it puts macrovar in the global table.

I don't quite understand your second question. Macro variables are resolved when referenced with &macrovar.

Could you be more specific?

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Contributor
Posts: 43

Re: call a macro inside call execute, and macro variables resolution

Thanks, I mean that for instance the macro would be:

%macro mmm(par1);

 

  proc sql;

  select var || put(time(),time10.) into :macrovar from dataset where par = &par1;

  quit;

     options something=&macrovar;

%mend;


meaning that for instance I need to use the macrovar variable (calculated within the macro) later in the same macro neither in a datastep nor in a proc step (in the example I'm using "options" which does not have any sense, it is just to explain what I mean). As you taught me, this code would not work because &macrovar is resolved at compile time (hence undefined).

How would you rewrite that line in order to use that macrovariable calculated just before? I'm looking for something like "options something=symget('macrovar');" (which is awful, I know).


Thanks again

Super User
Super User
Posts: 7,401

Re: call a macro inside call execute, and macro variables resolution

You wouldn't do it that way.  So say I want to do that bit of code:

%let par1=something;

data _null_;

     set dataset (where=(par=&par1.)); 

     call execute(cats('options something=',put(time(),time10.),';'));

run;


Note that the above will generate the options statement once for each record returned from dataset where the where condition is true. 

Super User
Posts: 6,936

Re: call a macro inside call execute, and macro variables resolution

If you want a "persistent" macro variable that keeps its value from macro call to macro call, you need to put it into the global macrovariable table by using the %global macrovar; statement.

Your initial problem was that, by using call execute within a data step, you created confusion about when what piece of code was executed. I advise to follow the KISS principle and not call a macro with call execute, but a "macro-less" version of the code with call execute, unless you completely know what you're doing (which will take some time regarding the use of the macro language).

I was alos initially baffled by your problem.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Regular Contributor
Posts: 198

Re: call a macro inside call execute, and macro variables resolution

your question does not make sense

> is there a function to resolve a macrovariable at execution-time without using neither a datastep nor a proc?

we have macro variables (%let)

and macro definitions (%macro x ... %mend xSmiley Wink

resolution means

1. substitution:

1.1 assignment %let a = apples;

1.2 substitution: %put I like &a;

also: %put info: &=a;

2. expansion:

2.1 definition: %macro do_loop(dim=3)%do i = 1 %to &dim; %put echo &=i;%end;%mend;

2.2 expand: %do_loop(dim=4)

%put i=1;

%put i=2;

%put i=3;

%put i=4;

summary:

macro variable values are referenced, substituted, with an ampersand before the macro variable name

macro definitions are expanded, with a percent sign before the macro definition name

please reframe your question

Super User
Super User
Posts: 6,499

Re: call a macro inside call execute, and macro variables resolution

Consider the timing of when the macro runs.

In your original line:

  call execute("%mmm(1)");

You are expanding the macro BEFORE the data step executes and storing the code generated by that macro into the literal string that you pass to call execute.

So the %PUT statements run BEFORE the data step starts and what is passed to CALL EXECUTE are the lines of code that the macro generated.  It is as if you coded

  call execute('proc sql; select ....');


If you change to using single quotes:

  call execute('%mmm(1)');

then the macro is expanded when it is pushed on the CALL EXECUTE stack.  So the %PUTs run while the code is being put onto the stack and the same SQL code is put on the stack to run after the data step finishes.


If you change to using %NRSTR() inside of single quotes:

  call execute('%nrstr(%%mmm)(1)');

then the macro call is pushed onto the CALL EXECUTE stack.  So now the %PUTs run after the data step has finished.


☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 9 replies
  • 634 views
  • 9 likes
  • 5 in conversation