Hi,
Thanks in advance for stopping by and helping.
I am getting an error while writing to a text file using PUT statement. If I remove the inner j loop, the program works fine. Here is the piece of problematic code:
put "%nrstr(%xx());"//
"options validavarname= v7;"//;
%do i=1 %to &n;
put "data &&fm&i.;"/
"set xx;"/
%do j = 1 %to &&cnt&i;
if type = 2 then
do;
if x ne y then
do;
put +2 x " = " y ";"//
end;
end;
%end;
"run;"//;
%end;Here is the error:
Please suggest the solution. Thanks again!
A tool that is good to learn for use in debugging macro related code, your %Do loops are macro code, is to turn on one or more options of Mprint, Symbolgen or Mlogic. Add something like
options MPRINT;
before the code in question when executed. Use Options nomprint; to turn off.
You should see that the resolved code in the LOG using the Mprint that you get a separate instruction code line of "run;" because your current' code does not have that quoted string as part of the argument for the PUT instruction. The current "If type= 2" and related code ends the PUT. So you need another PUT before the "run;".
Hint: It is usually a good idea to include the entire code for a data step or procedure that is having issues and better to include a small data set in the form of working data step code that could be used to test the code. Since your code doesn't define where the values of Type, X or Y variables come from I have to assume there is another data set involved and more code using that data set prior to what you have shown.
Your code does not appear to make much sense as written. And there are not any comments explaining what it is trying to do.
We could try to add some more code so that we can see what SAS code it is trying to generate.
%macro xx(); This is what XX emits. %mend xx;
%macro test;
put "%nrstr(%xx());"//
"options validavarname= v7;"//;
%do i=1 %to &n;
put "data &&fm&i.;"/
"set xx;"/
%do j = 1 %to &&cnt&i;
if type = 2 then
do;
if x ne y then
do;
put +2 x " = " y ";"//
end;
end;
%end;
"run;"//;
%end;
%mend test;
But to test it we will have to make a lot of assumptions about the macro variables it is referencing.
%let n=2;
%let fm=fm;
%let fm1=out1;
%let fm2=out2;
%let cnt=cnt;
%let cnt1=2 ;
%let cnt2=3;
Now we can try calling the macro in the middle of a data step and see what the data step compiler makes of the SAS statements the macro code generates.
options mprint;
data _null_;
%test;
run;
You can see that the macro generates that quoted string outside of any of the other SAS statements it generates.
MPRINT(TEST): put "%xx();"// "options validavarname= v7;"//;
MPRINT(TEST): put "data out1;"/ "set xx;"/ if type = 2 then do;
MPRINT(TEST): if x ne y then do;
MPRINT(TEST): put +2 x " = " y ";"// end;
MPRINT(TEST): end;
MPRINT(TEST): if type = 2 then do;
MPRINT(TEST): if x ne y then do;
MPRINT(TEST): put +2 x " = " y ";"// end;
MPRINT(TEST): end;
NOTE: Line generated by the invoked macro "TEST".
106 "run;"//;
______
180
MPRINT(TEST): "run;"//;
MPRINT(TEST): put "data out2;"/ "set xx;"/ if type = 2 then do;
MPRINT(TEST): if x ne y then do;
MPRINT(TEST): put +2 x " = " y ";"// end;
MPRINT(TEST): end;
MPRINT(TEST): if type = 2 then do;
MPRINT(TEST): if x ne y then do;
MPRINT(TEST): put +2 x " = " y ";"// end;
MPRINT(TEST): end;
MPRINT(TEST): if type = 2 then do;
MPRINT(TEST): if x ne y then do;
MPRINT(TEST): put +2 x " = " y ";"// end;
MPRINT(TEST): end;
NOTE: Line generated by the invoked macro "TEST".
106 "run;"//;
______
180
MPRINT(TEST): "run;"//;
ERROR 180-322: Statement is not valid or it is used out of proper order.
107 run;
NOTE: The SAS System stopped processing this step because of errors.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
But it is also generating other silly SAS statements, like:
MPRINT(TEST): put "data out2;"/ "set xx;"/ if type = 2 then do; MPRINT(TEST): put +2 x " = " y ";"// end;
Does your input dataset actually have variables named IF, TYPE , THEN, DO and END?
And that inner %DO loop over the macro variable J makes no sense becuase it is just generating the same code multiple times. Only way it makes sense is if those macro variables it is referencing can only have values of 0 or 1. In which case why not just use an %IF %THEN %DO block instead of %DO loop.
And how did you get those series of &&FM&I and &&CNT&I variables? Did you generate them from a dataset? Why not just use the data step that reads in that dataset to drive the loop instead of converting the dataset variables into macro variables and then passing the macro variables back a data step as quoted strings to then write out?
I do use mprint, symbolgen, etc options before macro but am not getting this Put statement. It's the first time I am trying to write to a file using PUT. So have a big time confusion where it is ending. I am pretty sure, there must be some issue ending this put statement in the J loop.
This code is part of bigger code and I don't know how much I can copy here. The 2 loops may not be making sense here but they are doing what they are supposed to do. I can try to explain here what they are for:
variable i has count for no. of datasets, for ex: 2 (A & B)
variable j has count of no. of variables in those datasets - For example A has 10 variables & B has 100. I am trying to assign these data variables to another variables and put out in a text file. So that I don't have to manually assign each variables.
I had tried as much I could... like adding the PUT statement before run ---> getting error:
If I add extra semi-colon before // , that is also not helping.
put +2 x " = " y ";" ; //
I am not exactly sure what your code is supposed to be doing either, but maybe you could try %PUT as shown below rather than PUT.
%let n=2;
%let fm=fm;
%let fm1=out1;
%let fm2=out2;
%let cnt=cnt;
%let cnt1=1 ;
%let cnt2=2;
%macro test;
%put /*"%nrstr(%xx());"//*/ /* commented this out since uncertain what it does */
options validavarname= v7; ;
%do i=1 %to &n;
%put %str(data &&fm&i.;) ;
%put %str(set xx;) ;
%do j = 1 %to &&cnt&i;
%put %str(if type = 2 then
do;
if x ne y then
do;
put +2 x " = " y ";"//
end;
end;) ;
%end;
%put %str(run;) ;
%end;
%mend;
options mprint mlogic symbolgen;
%test
The code posted does not make any sense at all. Please post the complete data step / macro.
I think you should tell us what the overall *goal* is, because most likely there is a much more straightforward way to output code to a file. Basically, you seem to be trying to write out code that is conditional on (or parameterized with) values from the data, but what is the purpose of that resulting code? What would be the goal of running that resulting code that could not be accomplished directly by the program / macro that's reading the data in the first place?
If you really do need to do this, I would just start very simple so that you can see what the code is actually doing, e.g.:
data _null_;
put "data somefile;"/"set indata;"/;
x=3; y=3;
if x=y then put x "=" y ";"/;
put "run;";
run;
...and then look at what that is writing to the log file (or wherever you've directed the output).
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.