code ,results are as followed,
why macro varable value when compared with normal var within macro environment happends an error ?
code
%macro comp;
data test;
do n = 1 to 5;
output;
end;
run;
data comp;
set test;
length k 3 d1 3 d2 3 d3 3;
%do i = 1 %to 3;
%if n > %eval(&i.) %then %do;
k=%eval(&i.);
d&i.=1;
output;
%end;
%end;
run;
%mend;
%comp;
expected :
n | k | d1 | d2 | d3 |
1 | 1 | |||
1 | 2 | |||
1 | 3 | |||
2 | 1 | 1 | ||
2 | 2 | 1 | ||
2 | 3 | 1 | ||
3 | 1 | 1 | ||
3 | 2 | 1 | 1 | |
3 | 3 | 1 | 1 | |
4 | 1 | 1 | ||
4 | 2 | 1 | 1 | |
4 | 3 | 1 | 1 | 1 |
5 | 1 | 1 | ||
5 | 2 | 1 | 1 | |
5 | 3 | 1 | 1 | 1 |
but actually:
n | k | d1 | d2 | d3 |
1 | 1 | 1 | ||
1 | 2 | 1 | 1 | |
1 | 3 | 1 | 1 | 1 |
2 | 1 | 1 | ||
2 | 2 | 1 | 1 | |
2 | 3 | 1 | 1 | 1 |
3 | 1 | 1 | ||
3 | 2 | 1 | 1 | |
3 | 3 | 1 | 1 | 1 |
4 | 1 | 1 | ||
4 | 2 | 1 | 1 | |
4 | 3 | 1 | 1 | 1 |
5 | 1 | 1 | ||
5 | 2 | 1 | 1 | |
5 | 3 | 1 | 1 | 1 |
Turn on the MRINT option so you can see what code your macro logic is generating.
The ASCII code for the lowercase letter N is always greater than the ASCII codes for any string of digits that the macro variable I might evaluate to. So your %IF test is always true where &I is 1 , 2 or 3. Which means that your macro %DO loop will generating these lines of SAS code for your data step to execute.
k=1;
d1=1;
output;
k=2;
d2=1;
output;
k=3;
d3=1;
output;
I suspect that you actually thought that your macro %IF statement could compare the variable N from the the dataset to the numbers 1, 2 and 3. But the macro code has finished running and doing its job of generating code before the generated data step begins running. You would need to use an IF statement instead of a %IF statement if you want to access the value of the variable N.
Of course if you want K to go from 1 to 3 then it is much easier to do that using a DO loop instead of trying to use a macro %DO loop to generate a bunch of assignment statements.
Also your expected output does not really depend on the value of N at all, so not sure why you added the comparison to N anyway.
Try something like this instead, macro code not required.
data test;
do n = 1 to 5;
output;
end;
run;
data comp;
set test;
do k=1 to 3 ;
array d (3);
do i=1 to k ;
d(i)=1;
end;
output;
end;
drop i;
run;
You are mixing datastep language and macro language which will not work. They are two separate pieces. Learn how to program using Base SAS first, then move onto the more advanced topic of macro creation. For this question, post example test data in the form of a datastep (so we can run it), and then show what you want the output to look like, there is nothing in the code you posted which can't be done in Base SAS.
Just adding to the correct answer of RW9. With a few exceptions, it is best to think of the SAS Macro language as a word processor, which does its work BEFORE the data step.
With this concept in mind, it seems nonsensical to have a macro %DO loop inside of data step--even if it doesn't throw an error. The macro statement will be evaluated before the data step is compiled, let alone executed.
When you think about it this way, you can see that RW9's response is correct--and deserves to be assigned the correct answer--even if you have to go back and rethink your problem!
Thx for your advice. i've made my way on
Hi,
I think you messed up the %macro statement. %macro statement is only used for macro variables. For example, in the line " %if n > %eval(&i.) %then %do;", n is not macro variable, it can not be used in %if statement. I wrote an update for your DATA STEP of comp. The output seems to be similar to your expectation.
data comp;
set test;
by n;
retain k d1 d2 d3;
if first.n then do;
call missing(d1,d2,d3);
k=1;
%do i = 1 %to 3;
k=&i.;
d&i.=1;
output;
%end;
end;
run;
let's move on !
Thx for your reply , i ran your code , but turned an error.
I've got an solution,
data test;
do n = 1 to 5;
output;
end;
run;
data comp;
set test;
do k=1 to 3 ;
array d (3);
do i=1 to k ;
if n >= i then d(i) = 1;
end;
output;
end;
run;
Turn on the MRINT option so you can see what code your macro logic is generating.
The ASCII code for the lowercase letter N is always greater than the ASCII codes for any string of digits that the macro variable I might evaluate to. So your %IF test is always true where &I is 1 , 2 or 3. Which means that your macro %DO loop will generating these lines of SAS code for your data step to execute.
k=1;
d1=1;
output;
k=2;
d2=1;
output;
k=3;
d3=1;
output;
I suspect that you actually thought that your macro %IF statement could compare the variable N from the the dataset to the numbers 1, 2 and 3. But the macro code has finished running and doing its job of generating code before the generated data step begins running. You would need to use an IF statement instead of a %IF statement if you want to access the value of the variable N.
Of course if you want K to go from 1 to 3 then it is much easier to do that using a DO loop instead of trying to use a macro %DO loop to generate a bunch of assignment statements.
Also your expected output does not really depend on the value of N at all, so not sure why you added the comparison to N anyway.
Try something like this instead, macro code not required.
data test;
do n = 1 to 5;
output;
end;
run;
data comp;
set test;
do k=1 to 3 ;
array d (3);
do i=1 to k ;
d(i)=1;
end;
output;
end;
drop i;
run;
sorry , i just put the wrong code.
here is the solution:
data test;
do n = 1 to 5;
output;
end;
run;
data comp;
set test;
do k=1 to 3 ;
array d (3);
do i=1 to k ;
if n >= i then d(i) = 1;
end;
output;
end;
run;
yeah!
An another solution is turnd %if .. %then to if...then..
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 the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.