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

Hello, I am trying to use a macro within CALL EXECUTE. The source data for the macro is a data set with two fields: Group and Employer. Group never has any special characters, but Employer may have an apostrophe. When I run the following code, I get the following error:

 

ERROR: Expected close parenthesis after macro function invocation not found.

 

This is a simplified version of my macro:

%macro test (Group,Employer); 
proc sql; 
create table test as
select distinct
	MemberID
	,"&Employer" as Employer
	,"&Group" as Group
from Membership
where EmployerID like "&Group%" 
	and Date between "01Jan2017"d and "31Dec2017"d 
;quit; 
%mend; 

This is the CALL EXECUTE code:

data _null_;
	set work.list;
	call execute('%nrstr(%deductible(
		 '||strip(Group)||'
		,'||strip(Employer)||'
	);)');
run;

As long as there are no special characters in the Employer field, my code runs without problem. The macro runs without problem, even with apostrophes, with: 

%test (123456,%bquote(O'Test Employer));

So I tried to use:

data _null_;
	set work.list;
	call execute('%nrstr(%deductible(
		 '||strip(Group)||'
		,%bquote('||strip(Employer)||')
	);)');
run;

How can I get SAS to ignore any apostrophes that my come up in the Employer field? Any help is appreciated, thank you!

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

You can avoid a lot of the timing issues with CALL EXECUTE by just writing to a file and using %INCLUDE instead.

filename code temp;
data _null_;
  set work.list;
  file code ;
  put '%deductible(%bquote(' group +(-1) '),%bquote(' employer +(-1) '));';
run;
%include code / source2;

View solution in original post

12 REPLIES 12
Shmuel
Garnet | Level 18

Have you tried %NRBQUOTE instead %BQUOTE ? 

rhachey
Calcite | Level 5

Yes, and I still get the same error.

PaigeMiller
Diamond | Level 26

Okay, let's start with the absolute basic fundamentals here.

 

You write a macro called %TEST, but then in CALL EXECUTE you are trying to run a macro called %DEDUCTIBLE.


Could this be the problem?

--
Paige Miller
rhachey
Calcite | Level 5

Sorry, in trying to simplify my code to post here, I forgot to change the %DEDUCTIBLE to %TEST in my post.

Tom
Super User Tom
Super User

One easy way is to allow your macro to accept actual quotes.

For example this macro will except values with or without quotes around them.

%macro test (Group,Employer);
%let group=%sysfunc(quote(%qsysfunc(dequote(%superq(group))),%str(%')));
%let employer=%sysfunc(quote(%qsysfunc(dequote(%superq(employer))),%str(%')));
proc sql;
create table test as
select distinct
   MemberID
  ,&Employer as Employer length=20
  ,&Group as Group length=20
from Membership
where EmployerID like &Group||'%'
  and Date between "01Jan2017"d and "31Dec2017"d
;
quit;
%mend;

Then call the macro with quoted values.

data _null_;
  set work.list;
  call execute(cats('%nrstr(%deductible)'
,'(',quote(trim(group),"'")
,',',quote(trim(employer),"'")
,')'
));
run;
PaigeMiller
Diamond | Level 26

Next thought

 

Instead of %NRBQUOTE or %BQUOTE, I think you really want %NRSTR to handle apostrophe's and other special characters. If it is a single apostrophe, rather then a pair, you might have to precede it with % as stated here: https://documentation.sas.com/?cdcId=pgmmvacdc&cdcVersion=9.4&docsetId=mcrolref&docsetTarget=n09tblr...

--
Paige Miller
Tom
Super User Tom
Super User

You can avoid a lot of the timing issues with CALL EXECUTE by just writing to a file and using %INCLUDE instead.

filename code temp;
data _null_;
  set work.list;
  file code ;
  put '%deductible(%bquote(' group +(-1) '),%bquote(' employer +(-1) '));';
run;
%include code / source2;
rhachey
Calcite | Level 5

Thank you, this works! But I don't understand how/why... can you explain the code a bit, or point me in the direction of resources? Especially the +(-1) piece. Thanks!

Tom
Super User Tom
Super User

The FILENAME statement will create a fileref to use for a temporary file.

The data step then writes to the file.

The %INCLUDE statement will execute the code in the file.

 

The data step reads the data and writes one line per observation using a simple PUT statement. The quoted text is written as is. The variable names reference variables in the input dataset. The pointer motion command removes the extra space that PUT adds when you write a variable in list mode (without a format specification). It does this by moving the pointer back one space so that the next thing written overwrites the space character.

Tom
Super User Tom
Super User

The pointer motion is only needed in this case because of the use of the %BQUOTE() function in the generated code.  That would quote the trailing space making it part of the value passed to the macro.  Since I don't have your macro I am not sure if that extra space would make a difference.  Normally in generated SAS code an extra space is not an issue.

 

If you name your macro parameters after your dataset variables (or visa versa) then PUT statement is even easier.  So if your macro had two parameters named VAR1 and VAR2 then your metadata dataset should have two variables named VAR1 and VAR2.

So a program like this:

data _null_;
 set metadata ;
 file code;
 put '%macro_name('  var1= ',' var2= ')';
run;

Will create code like:

%macro_name(var1=ABC ,var2=xyz )
%macro_name(var1=DEF ,var2=123 )

Remember that even if you define your macro to allow the parameters to be specified by position only (like: %my_macro(ABC,xyz) ) you can still use the parameter names in the call to the macro (like: %macro_name(var1=ABC ,var2=xyz ) ).

 

Astounding
PROC Star

A simple workaround would be to write the macro calls to a file instead of using CALL EXECUTE:

 


file mcalls temp;

data _null_;
  set list;
  file mcalls;
  put '%deductible(' strip(Group) ',' strip(Employer) ')';
run;

%include mcalls;
  

Note that the final semicolon is not necessary when calling a macro, and occasionally can harm the program's logic.

 

If the STRIP function causes problems, you should be able to just remove it:

 

put '%deductible(' group ',' employer ')';

 

If the single quotes cause problems, you can add %bquote back in:

 

put '%deductible(' group ', %bquote(' employer '))';

 

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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
  • 12 replies
  • 1091 views
  • 0 likes
  • 5 in conversation