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?
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.
@Reeza that was a copy and paste error. I tried using trim but the results are the same.
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));
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.
Well, that usually happens when a lines too long.
Try:
%include 'path to program.sas' /lrecl=500;
So to clarify.
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.
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 🙂
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.
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.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.