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

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 :

nkd1d2d3
11   
12   
13   
211  
221  
231  
311  
3211 
3311 
411  
4211 
43111
511  
5211 
53111

 

 

but actually:

nkd1d2d3
111  
1211 
13111
211  
2211 
23111
311  
3211 
33111
411  
4211 
43111
511  
5211 
53111
1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

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;

   

View solution in original post

11 REPLIES 11
RW9
Diamond | Level 26 RW9
Diamond | Level 26

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.

 

optimist55116
Calcite | Level 5

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! 

 

 

 

 

Reaven
Fluorite | Level 6

Thx for your advice. i've made my way on Cat Happy

MINX
Obsidian | Level 7

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;

 

MINX
Obsidian | Level 7
Thank you for your input. I learned a lot.
Reaven
Fluorite | Level 6

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;

Tom
Super User Tom
Super User

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;

   

Reaven
Fluorite | Level 6
thanks for you reply. u are right! But the variable n created just for test, it could be any numeric var. so i made a little change in your code ,then things got right!! 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;
Reaven
Fluorite | Level 6

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;

Reaven
Fluorite | Level 6

yeah!

 

An another solution is turnd %if  .. %then to if...then..

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

What is Bayesian Analysis?

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.

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
  • 11 replies
  • 7230 views
  • 3 likes
  • 5 in conversation