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

I am using a data step (although I could use proc sql)  to run through a list of names and generate a report.

the names are "Last Name, First Name".

I am getting: "ERROR: More positional parameters found than defined."

Here is sample code:

 

data namelist;

input ID GRP $4. NAME $25. ;

datalines;

01 ABCD Smith, John

02 WXYZ Jones, Dorothy

03 MNOP Garcia, Kimberly

;

%MACRO test_Report(ID, GRP, NAME);

%put ID;

%put &GRP;

%put &NAME;

%MEND;

 

data _NULL_;

set namelist; /* columns are ID Group and Name */

call execute( '%test_Report(' || strip(ID) || ',' || strip(GRP)  || ',' || %bquote(NAME) || ');' );

run;

 

What am I missing? There has to be a simple way of doing this. 

Thank you.

Stan

1 ACCEPTED SOLUTION

Accepted Solutions
novinosrin
Tourmaline | Level 20

HI @SSTEAD  slight adjustment to the syntax you used

 

data _NULL_;

set namelist; /* columns are ID Group and Name */

call execute
('%nrstr(%test_Report('||catx(',',ID,GRP,cat('%bquote(',NAME,')'))||'))');

run;

 

Some notes:

1. Your idea of %bquote(NAME) is very smart indeed. However you are better off  delaying the execution of the macro call until after the datastep is complete. 

2. Therefore you would need the %nrstr to delay the macro statements execution as the call can independently execute without having to bother with the datastep compiler.

3. In my humble opinion, it is better to not marry macro processor and execution unless absolutely needed, albeit the marriage most likely will end in a divorce.

View solution in original post

7 REPLIES 7
RichardDeVen
Barite | Level 11

You will need the macro invocation to mask the commas in the passed argument.  This is most often done with %STR().

 

So you want the requested code to be executed to look like

 

%test_Report( <ID>, <GRP>, %STR(<LAST>,<FIRST>) )

Very often CALL EXECUTE statements are desired to have their submissions all occur after the DATA step completes.   This can be accomplished by wrapping the submitted code in %NRSTR().  So the 'dispatching' data _null_ would be

 

 

data _NULL_;
  set namelist; /* columns are ID Group and Name */

* compute source code for macro invocation; macro_call_source_code = '%test_report(' || catx (',', ID, GRP, '%str(' || NAME || ')' ) /* wrap name in %STR source code to allow comma containing argument to be passed */ || ')' ;
* submit computed source code; call execute( '%nrstr(' || trim(macro_call_source_code) || ')' ); run;

 

 

 

SSTEAD
Obsidian | Level 7
Thank you. This works well and is pretty easy to understand. It does create another variable, but is very clear.
Tom
Super User Tom
Super User

If the macro is expected to get names that contain commas then write the macro in a way that it is expecting the values provided to have quotes. 

%MACRO test_Report(ID, GRP, NAME);
%local name2;
%put ID value is &ID;
%put GRP value is &GRP;
%put NAME with quotes is &NAME;
%let name2=%sysfunc(dequote(&name));
%put NAME without qutoes is &NAME2;
%MEND;

Then provide the quotes in the call.

filename code temp;
data _NULL_;
  set namelist; /* columns are ID Group and Name */
  file code;
  put '%test_Report('  id= ',' grp= ',' name= :$quote. ')';
run;
%include code / source2;
SSTEAD
Obsidian | Level 7
Thank you. I frequently use this trick. I like the ability to review what was written and check it for debugging, and did this earlier in development.
novinosrin
Tourmaline | Level 20

HI @SSTEAD  slight adjustment to the syntax you used

 

data _NULL_;

set namelist; /* columns are ID Group and Name */

call execute
('%nrstr(%test_Report('||catx(',',ID,GRP,cat('%bquote(',NAME,')'))||'))');

run;

 

Some notes:

1. Your idea of %bquote(NAME) is very smart indeed. However you are better off  delaying the execution of the macro call until after the datastep is complete. 

2. Therefore you would need the %nrstr to delay the macro statements execution as the call can independently execute without having to bother with the datastep compiler.

3. In my humble opinion, it is better to not marry macro processor and execution unless absolutely needed, albeit the marriage most likely will end in a divorce.

SSTEAD
Obsidian | Level 7
Thank you so much. This works perfectly. I frequently use a data step to generate a list of MACRO calls that I then include, similar to one of the other replies.
novinosrin
Tourmaline | Level 20

You're welcome. Anyways, It was your solution that needed a slight adjustment. I wouldn't want to take that credit away from you. 

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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
  • 7 replies
  • 1234 views
  • 0 likes
  • 4 in conversation