BookmarkSubscribeRSS Feed
Macro
Obsidian | Level 7

I have defined macro variables nclass, n0, n1, ..., n&nclass, and response, then I have the following code:

proc sql undo_policy=none;

  create table temp as

  select *,

         case

           %do k=1 %to &nclass;

               when &n%eval(&k-1) le myvar le &&n&k then %scan(&response,&k," ")

           %end;   

           else .   

         end as RC

  from temp;

quit;

The problem with the above code is: &n%eval(&k-1), there is no problem with &&n&k.

Basically it evaluates &n then combine with 0 when k=1. If n is not defined, then it will have unresolved macro variable N problem; if n is defined as 357, for instance, then it will give 3570 for

&n%eval(&k-1) when k=1. What I really want is the value of macro variable n0.  Even when I use &&n%eval(&k-1), it still does not work. How can I represent the value of n0 when k=1?

11 REPLIES 11
DMoovendhan
Quartz | Level 8

Just Use 'n%eval(&k-1)' this should work.

when you use &n%eval(&k-1), sas will consider n as mactro variable, but now it will be considered a string for macro processing and after that it will be considered as n0,n1--- accordingly after the macro variable resolution....

Macro
Obsidian | Level 7

This does not work. I would like the value of n%eval(&k-1) instead of the name of it.

RW9
Diamond | Level 26 RW9
Diamond | Level 26

Hi,


What are you attempting to do.  Provide test data and example output.  I would avoid using macro lists and loops to scan over these, its gets complicated and messy.  Have a look at array processing for instance.

Assuming dataset of:

A          B          N1NCLASS     N2NCLASS     N3NCLASS     N1K     N2K     N3K     N1RESPONSE     N2RESPONSE     N3RESPONSE

Then code such as:
data want;

     set have;

     array nvals{3} n1nclass n2nclass n3nclass;

     array kvals{3} n1k n2k n3k;

     array rvals{3} n1response n2response n3response;

     do I=2 to 3; /* Note 1 does not have a -1! */

          if nvals{I-1} le kvals{I} then result=scan(rvals{I},i," ");

     end;

run;

Of course, if you number your variables such:

NCLASS1 NCLASS2 NCLASS3, NK1 NK2 etc.

then you can also use the - to show list which will shrink your code.

data want;

     set have;

     array nvals{3} n1nclass-n3nclass;

Macro
Obsidian | Level 7

While arrray is an alternative and helpful sometimes, but it is not macro programming. The response variable is a input parameter. Can we use arrray as an input parameter of a macro program?

RW9
Diamond | Level 26 RW9
Diamond | Level 26

Its hard to tell, as there is no full code to show what you are doing.  My first question would be why do you need reponse var as a parameter, or have this in a macro at all?  Put response var in a dataset, then use joins to get the result rather than a where clause.  Best bet, provide some test code/data and what you want out of it.

DMoovendhan
Quartz | Level 8

Use this code this should work,

%sysfunc(cat(&n,%eval(&k-1)))

The error is mainly because the values &n and %eval are considered as different macro invocations, I thought that if we can make this concatinated.

This resolves the value, but the warning is still there.

I tried it with below code,
%let n1 = afdsjhysadjh;
%let k = 2;
%put %sysfunc(cat(&n,%eval(&k-1)));

ballardw
Super User

%let j= %eval(&k-1);

when &&n&j le myvar le &&n&k then %scan(&response,&k," ")

Macro
Obsidian | Level 7

If you check my above code, you see it was in a sql case structure. I guess you cannot use %let j= %eval(&k-1) in the case structure. That is why I did not assign %eval(&k-1) to an auxilary variable. Do you have other ways?

ballardw
Super User

Why do you say that the %let j= can't be used in the case structure?

Tom
Super User Tom
Super User

To do that type of relative name expansion it is easier if you make a new variable to hold the name.

%let n0=000;

%let k=1 ;

%let name=n%eval(&k-1);

%put &&&name ;

So your loop could be re-written as :

%do k=1 %to &nclass;

   %let previous=n%eval(&k-1);

   %let current=n&k;

   when &&&previous le myvar le &&&current then %scan(&response,&k," ")

%end; 

But you can eliminate the N0,N1,... macro variables and just make a delimited list of values like you have a delimited list of responses.

%let values=0 10 20 ;

%let responses=X Y Z ;

%let nclass=%sysfunc(countw(&values,%str( )));

...

   case

%do k=1 %to &nclass-1;

   when %scan(&values,&k,%str( )) <= MYVAR <= %scan(&values,&k+1,%str( ))

   then %scan(&response,&k,%str( ))

%end; 

   else %scan(&response,&nclass,%str( ))

   end

Fraktalnisse
SAS Employee

I believe that this question has already been answered, but here is yet another solution:

when %unquote(%nrstr(&n)%eval(&k-1)) le myvar le &&n&k then %scan(&response,&k," ")

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!

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
  • 11 replies
  • 1463 views
  • 1 like
  • 6 in conversation