BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
VSht
Obsidian | Level 7

Hi,

We have a process where '%ED' macro is executed, which calls 'Template.sas', which in turn calls 'Calculator_ED.sas'.

Inside Calculator.sas there is a macro %createindex, which performs conditional processing based on &classification_option macro variable. &Classification_option is defined through %let statement in 'Template.sas' and equals to &Flag. &Flag value is assigned inside %ED macro.

When I run %ED macro the process works. However, we had to build a 'control' table which determines which process will be run and then %ED macro is invoked through CALL EXECUTE. The addition of this step breaks the process.

Any insights are greatly appreciated. 

A simplified process is shown below:

 

I. This works:

%ED(YEAR=20);

 

II. This does not work:

FILENAME ctrl "Path\Test.csv";

* Table contents:

* Macro = ED;

* Year  = 20;

DATA WORK.Control;

    FORMAT

        Macro            $CHAR8.

        Year             BEST2.;

    INFILE ctrl

        LRECL=50

        delimiter=','

        MISSOVER

        DSD

        firstobs=2

    INPUT

        Macro            : $CHAR8.

        Year             : ?? BEST2.;

RUN;

 

DATA _NULL_;

       SET Control;

       arg = cats('%',Macro,'(Year=',Year,')');

       CALL execute(arg);

RUN;

 

WARNING: Apparent symbolic reference ABF_CLASSIFICATION not resolved.

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:   &CLASSIFICATION_OPTION. < 3

ERROR: The macro CREATEINDEX will stop executing.

 

Macro ED

%Macro ED(YEAR=);

 

%let Model = 'Path\TEMPLATE.sas';

 

* Flag = 1;

data ED_INPUT;

set Original_data;

where Flag = 1;

run;

%let Flag = 1; 

%include "&Model";

data ED_1;     set ED_Output;run;

 

* Flag = 0;

data ED_INPUT;

set Original_data;

where ABF_Flag = 0;

run;

%let Flag = 0;

%include "&Model";

data ED_2;     set ED_Output;run;

%Mend;

 

 

TEMPLATE.sas

Contains:

%let CLASSIFICATION_OPTION = &Flag;

%include "&LOCATION.\CALCULATOR_ED.sas";

 

CALCULATOR_ED.sas

Contains macro definition and macro call for %macro createindex;

That macro executes conditional processing based on &CLASSIFICATION_OPTION:

 

%if &CLASSIFICATION_OPTION. < 3 %then %do;

[actions]

%end;

 

%else %if &CLASSIFICATION_OPTION. = 3 %then %do;

[actions]

%end;

 

%else %if &CLASSIFICATION_OPTION. = 4 %then %do;

[actions]

%end;

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Timing.  Don't let SAS run the macro will you are pushing it onto the stack to run after the data step.

data _null_;
  set control;
  call execute(cats('%nrstr(%',macro,')(year=',year,')'));
run;

Now the macro call %ED(year=20) will be pushed onto the stack instead of the code that running %ED() generates.

 

Plus your SAS log will be a lot easier to read.

 

View solution in original post

6 REPLIES 6
Tom
Super User Tom
Super User

Timing.  Don't let SAS run the macro will you are pushing it onto the stack to run after the data step.

data _null_;
  set control;
  call execute(cats('%nrstr(%',macro,')(year=',year,')'));
run;

Now the macro call %ED(year=20) will be pushed onto the stack instead of the code that running %ED() generates.

 

Plus your SAS log will be a lot easier to read.

 

VSht
Obsidian | Level 7

Thank you!!! Works perfectly and you are right - the log is clear and easy to read.

Should one always add %nrstr when using CALL EXECUTE?

Tom
Super User Tom
Super User

It depends on the code you are pushing with CALL EXECUTE().

If you are just pushing regular SAS statements then you normally do not care as the macro processor will ignore those strings anyway.

If actually want the macro to run when the CALL EXECUTE() is running then don't include the %NRSTR().  So if the macro call is just going to execute macro statements AND you need the datastep to retrieve the modified macro variable values later in the same step (via other CALL EXECUTE() steps or via SYMGET() function call).

If the macro does not have conditional logic that depends on the execution of the SAS code that the macro generates then you won't have a timing issue if you leave off the %NRSTR().  You will just get a messy SAS log.

VSht
Obsidian | Level 7
I never had this issue before. I have to learn more about this. Your explanation sets me in the right direction. Thank you.
Tom
Super User Tom
Super User

I usually only wrap the %NRSTR() around the macro reference itself, not the arguments.

call execute(cats('%nrstr(%mymacro)(',var1,',',var2,')'));

But that can depend on what values you are passing.  If you want to have an argument that references a macro variable generated by the running of generated code then quote that reference also.

VSht
Obsidian | Level 7
Tank you. I will definitely experiment with this.:)

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 797 views
  • 3 likes
  • 2 in conversation