2
votes

I'm using SAS 9.1.3 to call a macro in a DATA step, but the macro generates a PROC REPORT step, so I am using CALL EXECUTE to call it, generate all those PROC REPORT steps, and then execute them all after the DATA step.

I'm using an array, and the macro is executed each time for every element in this array:

DATA macro_test;
  ARRAY questions[3] $ 32 ('question1' 'question2' 'question3');

  DO i=1 to 3;
    a_question = questions(i);
    CALL EXECUTE( "%report_by_question(a_question)" ); 
  end;

RUN;

The thing is, the report outputs are coming out (usually) backwards - it will print question3 first, then 2, then 1.

Is there a way to modify the execution order of CALL EXECUTE so I can have the question reports print in order, or does it just do its own thing?

Thanks!

3

3 Answers

5
votes

I assume you mean something more like this for yout call execute() line:

 CALL EXECUTE( "%report_by_question(" || trim(left(a_question)) || ");" ); 

With a test macro I get some log lines like this, showing that the call execute()s are happening in the right order. Do you get anything similar?

Macro

%macro report_by_question(a);
data test_&a;
  do i=1 to 10000000;
    output;
  end;
run;
%mend;

Logs

NOTE: CALL EXECUTE generated line.
1   + data test_question1;   do i=1 to 10000000;     output;   end; run;

NOTE: The data set WORK.TEST_QUESTION1 has 10000000 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           6.14 seconds
      cpu time            0.45 seconds


1   +                                                                   ;
2   + data test_question2;   do i=1 to 10000000;     output;   end; run;

NOTE: The data set WORK.TEST_QUESTION2 has 10000000 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           3.87 seconds
      cpu time            0.53 seconds


2   +                                                                   ;
3   + data test_question3;   do i=1 to 10000000;     output;   end; run;

NOTE: The data set WORK.TEST_QUESTION3 has 10000000 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           3.12 seconds
      cpu time            0.45 seconds
2
votes

A data step is compiled and then executed. The call execute(str); pushes the str into the input queue, so that they are popped after the data step is done execution. The order is preserved, period.

However, if you put your macro invocation in the double quoted string as you do in: call execute("%report(q)"); then the macro is invoked when the data step is compiled, which is even before the data step starts running.

If you don't want to invoke the macro in the compile time, then either macro quote it or put it in the single quoted string. Below is an example. Hope this helps.

/* create a dataset with 1 var and 3 obs */
data qs;
  input q $;
cards;
q1
q2
q3
;
run;

/* reporting macro -- a mockup */
%macro report(q=);
  %put report for q=&q;
%mend  report;

/* call the reporting macro for each q */
data _null_;  
  set qs;     
  macro = catx(q, '%report(q=', ')'); 
  call execute(macro);
run;

/* on log
report for q=q1
report for q=q2
report for q=q3
*/


/* to show what happens when the
   macro is invoked during the compile
   time */
data _null_;
  call execute("%report(q=q1)");
  put "after call execute";
run;
/* on log
1   data _null_;
2     call execute("%report(q=q1)");
report for q=q1
3     put "after call execute";
4   run;
after call execute
*/
1
votes

I prefer to do everything macro related using macro language. I guess the trade-off is that you have little macros scattered throughout your program. However, to prevent your program from generating reports, just comment out the macro call (*%loopit;) Also, you don't have to type out "question1", "question2", "question3", etc!!!
Hopefully this is useful to you!

%macro report_by_question(input);
    %put "Question: " &input;
%mend;

%macro loopit;
    %do i=1 %to 3;
        %report_by_question("question&i.");
    %end;
%mend loopit;
%loopit;