BookmarkSubscribeRSS Feed
dwsmith
Obsidian | Level 7

I have a SAS program (let's call it program1) that calls another SAS program to execute using %include (let's call it program2). If I run program2, on its own, the program executes perfectly fine. However, if I run program1, program2 fails when called by %include:

SYMBOLGEN:  Macro variable PROD_GRP resolves to mttt
"mttt"
SYMBOLGEN:  Macro variable PROD_GRP resolves to mttt
MPRINT(SOS_MACH):   data serno_ mttt;
SYMBOLGEN:  Macro variable PROD_GRP resolves to mttt
MPRINT(SOS_MACH):   set serials2_ mttt;
ERROR: File WORK.SERIALS2_.DATA does not exist.
MPRINT(SOS_MACH):   eqp_id = trim(ser_no) || "CAT";
MPRINT(SOS_MACH):   run;

We can see from symbolgen, there is no leading white space, but from mprint, SAS has inserted a leading white space.

 

Here is the code snippet that it is erroring on.

data prod;
 format names $5.;
 input names;
 datalines;
 mttt
 pipe
 ttl
 ;
run;
data _null_;
 set prod nobs = n;
 call symputx ('cnt', n);
run;

%macro sos_mach; %local i prod_grp; %do i = 1 %to &cnt; data _null_; set prod (obs = &i firstobs = &i); call symputx ('prod_grp', names); run; %put "&prod_grp"; data serno_&prod_grp; set serials2_&prod_grp; eqp_id = trim(ser_no) || "CAT"; run; %end; %mend sos_mach;

I am using symputx which would remove any leading or trailing white spaces as well.

 

How can I correct this problem that only occurs when program2 is called in program1 with a %include?

 

 

23 REPLIES 23
Reeza
Super User

You can apply the trim/strip function to remove spaces. Your data step shows a leading space in the variable that might be read in. 

 

I didn't think you could use cards inside a macro, I'm surprised that's not causing issues, unless its just for demo purposes.

 

You're calling your macro within itself? You appear to have an extra %macro sos_mach in the middle of your code?

 

This doesn't seem to make a lot of sense...I feel we're missing something important here. 

dwsmith
Obsidian | Level 7

@Reeza that was a copy and paste error. I tried using trim but the results are the same.

Reeza
Super User

Ok...I don't see that issue, so I think you have an extra space in your variable somehow. Try using strip/compress to remove space in call symputx even though it seems redundant. 

 

The following generates expected values, no modifications - does it for you?

Post your log from the following if it doesnt:

 

data prod;
 format names $5.;
 input names;
 datalines;
 mttt
 pipe
 ttl
 ;
run;
data _null_;
 set prod nobs = n;
 call symputx ('cnt', n);
run;
%macro sos_mach;
%local i prod_grp;
%do i = 1 %to &cnt;
	data _null_;
		set prod (obs = &i firstobs = &i);
		call symputx ('prod_grp', names);
	run;
	%put "serno_&prod_grp";
%end;
%mend sos_mach;

%sos_mach;

Otherwise change your call symputx to the following and let me know if that works. Your data step does show an extra blank before the mttt so I wonder if it's not being read in properly or if there's an invisible character somewhere. 

 

call symputx ('prod_grp', strip(names));

 

dwsmith
Obsidian | Level 7
@Reeza strip and trim produce the same log as I posted
Reeza
Super User

Can you attach your test data set?

 

Also, please post the new log from my code - not yours. I want to see what the test code exactly returns. 

If it works, then it's an issue with your data.

dwsmith
Obsidian | Level 7
@Reeza there isn't anything wrong with the data or code. It works perfectly fine when not being called by %include. It only fails when being called from another program via %include.
Reeza
Super User

Well, that usually happens when a lines too long.

 

Try:

%include 'path to program.sas' /lrecl=500;
dwsmith
Obsidian | Level 7
@Reeza same issue occurred.
Reeza
Super User

So to clarify. 

  • Your code works fine when run in editor. 
  • If you use %include it doesn't?

 

Please show how you're using the %include

 

Regarding @RW9 code - look up call execute. It generates the datastep code to create a data set for each group, which is what you want.  You can also use it to call your macro instead of looping.  Or you can use it as he did. It is more efficient as a solution, but if your %include doesn't work it won't work either. 

dwsmith
Obsidian | Level 7
@Reeza yes, the code works fine on its own.

%include "&DIR.\all moves - SOS data grab.sas";

The directory is correct. I checked it 100s of times. I also copied and paste the SAS file name. Other %include calls with this directory work fine as well.
Reeza
Super User

I agree with @RW9 though, this isn't a good way to achieve the desired results, but also curious as to why it won't work 🙂

RW9
Diamond | Level 26 RW9
Diamond | Level 26

Hi,

 

Can I ask what you are attempting to do with that code?  It seems to be a convoluted method to create lots of datasets from a list?  Why would you want to split the data up, have a variable which contains the group, and then use by group processing, it is far easier to program, and less resouce hungry.  Keep it as simple as possible.  

If you really have to go down that road, then why not just do:

data prod;
  length names $10;
  input names;
  call execute(cats('data serno_',names,'; set serials2_',names,';eqp_id=cats(ser_no,"CAT"); run;');
datalines;
mttt
pipe
ttl
;
run;

No need to go through all that macro stuff.  If you can clarify what your doing then I can provide further advice.

dwsmith
Obsidian | Level 7
@RW9 I don't understand your code.
RW9
Diamond | Level 26 RW9
Diamond | Level 26

A datastep is a loop, over each observation the code in the datastep section (bearing in mind conditional branching) is executed for that observation.  Thus the code:

data prod;
  length names $10;
  input names;
  call execute(cats('data serno_',names,'; set serials2_',names,';eqp_id=cats(ser_no,"CAT"); run;');
datalines;
mttt
pipe
ttl
;
run;

Will create the SAS code:

data serno_***; set serials2_***; eqp_id=cats(ser_no,"CAT"); run;

For each observation in the dataset, and replace the *** with the names value in each case.  Hence no need for any looping, or macro code.

 

However my main point was regarding the splitting of the dataset in the first place.  Why do you want 3 datasets:

serno_mtt, serno_pipe, serno_ttl

All three will be the same, it doesn't make sense.  If yuo have to have 3 "copies" of it then:

data want;
  length name $200;
  set serials2 (in=a) serials2 (in=b) serials2 (in=c);
  if a then name="mtt";
  if b then name="pipe";
  if c then name="ttl";
run;

Then run further processing based on by groups:

proc means data=want;
  by name;
  ...
run;

Far more efficient in both programming and processing.  Am no longer at work so can't test code.

 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 23 replies
  • 2191 views
  • 2 likes
  • 5 in conversation