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

Hi,

I write a macro and now the step to call it.

I can list from line to line such as:

%mymacro(age=1);

%mymacro(age=2);

...

Instead I try 2 different method and the one with SQL and %put still works but generate all kind of error notice.

Can you tell me why and how to fix it?

 



data have; set sashelp.class;run;

%Macro mymacro(age = );
data _temp; set have;
if age=&age;run;
			*if too small number of record --> no running code;
			proc sql;	select count(*) into: NOBS from _temp; quit;
	%IF &NOBS>=4 %THEN %DO;
		DATA A_&age; SET _temp; RUN;
	%END;
%Mend;

proc sort data=have  out=name_value (keep=age) nodupkey; by age;run;


*Method 1: work directly with file;
data _null_;
  set name_value;
  call execute(catt('%nrstr(%mymacro)(age=', age, ');'));
run;


*Method 2: create command first;
*create list of %mymacro(age=   ) for macro run;
data name_value;set name_value;
string =    catt('%mymacro(age=', age, ');');
run;

proc sql noprint;
select string into :codeline separated by ' ' from name_value; quit;

%put &codeline;
1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

You are getting a timing issue with when the macro runs and when the code that the macro generates runs.

When you call it normally as the macro runs the code it generates runs.  So the SQL code that sets NOBS macro variable runs and then the macro tests its values.

But when you use CALL EXECUTE() to run it, without the %NRSTR(), then the macro runs while CALL EXECUTE is pushing code onto the stack to run after the data step finishes. So the PROC SQL code gets generated, but it won't execute until after the data step finishes. So the %IF statement that is checking NOBS macro variable is either not finding the variable to finding some value that was already set before the data step (the one running the CALL EXECUTE) started running.

 

Check the difference in the lines with + that CALL EXECUTE shows in the log.  When you protect the macro call you will see lines like:

+%mymacro(age=1);

When you don't then instead you see lines like:

+data _temp; 
+set have;

 

Similarly if you put a %PUT in front of the macro call then it will "eat" the DATA _TEMP; statement.  So instead of running:

data _temp; set have;

You are asking SAS to run:

%put data _temp; 

set have;

Now the SET statement has no DATA statement before it.

The other calls included into the macro variable should work fine.

 

View solution in original post

4 REPLIES 4
Reeza
Super User

Remove the %PUT. 

 

Otherwise the code is:

 

%PUT %mymacro(age=11);;

Which isn't valid code. If you just have:

 

&codeLine;

It resolves to the following which is valid.

 

%mymacro(age=11);

FYI - you may want to add the NOPRINT option to your SQL code to avoid output to the RESULTS pane.

 


@hhchenfx wrote:

Hi,

I write a macro and now the step to call it.

I can list from line to line such as:

%mymacro(age=1);

%mymacro(age=2);

...

Instead I try 2 different method and the one with SQL and %put still works but generate all kind of error notice.

Can you tell me why and how to fix it?

 



data have; set sashelp.class;run;

%Macro mymacro(age = );
data _temp; set have;
if age=&age;run;
			*if too small number of record --> no running code;
			proc sql;	select count(*) into: NOBS from _temp; quit;
	%IF &NOBS>=4 %THEN %DO;
		DATA A_&age; SET _temp; RUN;
	%END;
%Mend;

proc sort data=have  out=name_value (keep=age) nodupkey; by age;run;


*Method 1: work directly with file;
data _null_;
  set name_value;
  call execute(catt('%nrstr(%mymacro)(age=', age, ');'));
run;


*Method 2: create command first;
*create list of %mymacro(age=   ) for macro run;
data name_value;set name_value;
string =    catt('%mymacro(age=', age, ');');
run;

proc sql noprint;
select string into :codeline separated by ' ' from name_value; quit;

%put &codeline;

 

Tom
Super User Tom
Super User

You are getting a timing issue with when the macro runs and when the code that the macro generates runs.

When you call it normally as the macro runs the code it generates runs.  So the SQL code that sets NOBS macro variable runs and then the macro tests its values.

But when you use CALL EXECUTE() to run it, without the %NRSTR(), then the macro runs while CALL EXECUTE is pushing code onto the stack to run after the data step finishes. So the PROC SQL code gets generated, but it won't execute until after the data step finishes. So the %IF statement that is checking NOBS macro variable is either not finding the variable to finding some value that was already set before the data step (the one running the CALL EXECUTE) started running.

 

Check the difference in the lines with + that CALL EXECUTE shows in the log.  When you protect the macro call you will see lines like:

+%mymacro(age=1);

When you don't then instead you see lines like:

+data _temp; 
+set have;

 

Similarly if you put a %PUT in front of the macro call then it will "eat" the DATA _TEMP; statement.  So instead of running:

data _temp; set have;

You are asking SAS to run:

%put data _temp; 

set have;

Now the SET statement has no DATA statement before it.

The other calls included into the macro variable should work fine.

 

hhchenfx
Rhodochrosite | Level 12

Very detail explanation! 

Thanks a lot as usual, Tom.

HHC

CJac73
Obsidian | Level 7
Look at DOSUBL instead of EXECUTE

sas-innovate-wordmark-2025-midnight.png

Register Today!

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 4 replies
  • 1116 views
  • 5 likes
  • 4 in conversation