What's wrong with this Macro variable &&set%eval(&i+1)

Accepted Solution Solved
Reply
Occasional Contributor
Posts: 17
Accepted Solution

What's wrong with this Macro variable &&set%eval(&i+1)

Hi all,

 

I have some codes as below:

 

%let set1=cards;
%let set2=commute;
%let set3=demossubmit;
%let set4=financial;
%let set5=gadgets;
%let set6=other;
%let set7=pets;
%let set8=political;
%let set9=response;
%let set10=tele;

 

%macro join;
%do i=1 %to 9;
proc sql;
create table join%eval(&i+1) as
select *
from join&i
full join
&&set%eval(&i+1)
on join&i..custid=&&set%eval(&i+1).custid;
quit;
%end;
%mend;
%join

 

But here is the SAS log:

 

MPRINT(JOIN): proc sql;
WARNING: Apparent symbolic reference SET not resolved.
NOTE: Line generated by the macro variable "I".
1 &set
-
22
200
WARNING: Apparent symbolic reference SET not resolved.
NOTE 138-205: Line generated by the macro variable "I".
1 &set
-
22
ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, (,
CONNECTION, DICTIONARY.

ERROR 200-322: The symbol is not recognized and will be ignored.

ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string,
a numeric constant, a datetime constant, a missing value, BTRIM, INPUT, PUT,
SUBSTRING, USER.

 

Obviously, something is wrong with the Macro variable &&set%eval(&i+1). But how to fix it?  I tried &&set&i, and it worked. But once I use &&set%eval(&i+1), it didn't work.   

 

Thank you!


Accepted Solutions
Solution
‎02-16-2016 11:34 PM
Super User
Super User
Posts: 6,844

Re: What's wrong with this Macro variable &&set%eval(&i+1)

[ Edited ]

You are confusing the macro processor by trying to generate a variable name on the fly with a macro function.  Basically the parser is seeing a hard token break between "set" and "%eval".  Just add an extra step. For example:

 

%let set2=yes;
%let i=1 ;

%put This fails: &&set%eval(&i+1);

%let varname=set%eval(&i+1);
%put This works: &&&varname ;

%let j=%eval(&i+1);
%put This also works: &&set&j ;

View solution in original post


All Replies
Super Contributor
Posts: 259

Re: What's wrong with this Macro variable &&set%eval(&i+1)

Not a good solution but work around to create %let j =%eval(&i+1); and then use j

 

 

%let set1=cards;
%let set2=commute;
%let set3=demossubmit;
%let set4=financial;
%let set5=gadgets;
%let set6=other;
%let set7=pets;
%let set8=political;
%let set9=response;
%let set10=tele;

 

%macro join;
%do i=1 %to 9;

%let j =%eval(&i+1);
proc sql;
create table join%eval(&i+1) as
select *
from join&i
full join
&&set&j

 


on join&i..custid=&&set&j.custid;
quit;
%end;
%mend;
%join

Occasional Contributor
Posts: 17

Re: What's wrong with this Macro variable &&set%eval(&i+1)

Hi,

 

It worked! Only needs a tiny change: 

 

                                 on join&i..custid=&&set&j...custid;

 

It needs three dots~~ Smiley Happy

 

With one dot, it resovles to &set1custid;

With two, it resolves to cardscustid;

With three, it resolves to cards.custid~~

 

Thank you so much for your reply! 

 

Super Contributor
Posts: 339

Re: What's wrong with this Macro variable &&set%eval(&i+1)

Try %SuperQ:

 

%SuperQ(set%eval(&i+1))

on join&i..custid=%SuperQ(set%eval(&i+1)).custid;

 

(And maybe Call Exectute could avoid some macro-variable-chains)

Super User
Posts: 7,422

Re: What's wrong with this Macro variable &&set%eval(&i+1)

on join&i..custid=&&set%eval(&i+1).custid;

This looks like an honourable mention in the Obfuscated SAS Code Contest Smiley Wink

 

Instead of doing it in one step, try to build your macro values step-by-step. This makes it much easier to follow the logic.

And when debugging, you can use %put along every step to see where something goes wrong.

Keep in mind:

"Simple" always trumps "Clever"!

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Occasional Contributor
Posts: 17

Re: What's wrong with this Macro variable &&set%eval(&i+1)

Thank you!

Super User
Posts: 9,867

Re: What's wrong with this Macro variable &&set%eval(&i+1)

It look like you can't use macro variable in this way. Add one more statement if you could.

 

%let set1=cards;
%let set2=commute;
%let set3=demossubmit;
%let set4=financial;
%let set5=gadgets;
%let set6=other;
%let set7=pets;
%let set8=political;
%let set9=response;
%let set10=tele;
 
%macro join;
%do i=1 %to 9;

%let j=%eval(&i+1);


 &&set&j
%end;
%mend;
%join

 

 

Super User
Posts: 9,867

Re: What's wrong with this Macro variable &&set%eval(&i+1)

Or %SUPERQ() .

 

 

%let set1=cards;
%let set2=commute;
%let set3=demossubmit;
%let set4=financial;
%let set5=gadgets;
%let set6=other;
%let set7=pets;
%let set8=political;
%let set9=response;
%let set10=tele;
 
%macro join;
%do i=1 %to 9;
 %superq(set%eval(&i+1))
%end;
%mend;
%join
Super User
Super User
Posts: 7,711

Re: What's wrong with this Macro variable &&set%eval(&i+1)

Well, most things I would say.  This is what is nicely entitled Obfuscation.  The question should be why are you doing it this way in the first place, I can guarentee there is a far better methods to achieve your goal.  If you can post a small subset of data (couple of rows in the form of a dataset) and what the output should look like I will provide some code.  As a suggestion off the top of my head with no test data I would put the setx macro variables in a dataset and change the code accordingly - remember Base SAS is the programming language, macro is just a text generator.

Super User
Posts: 5,362

Re: What's wrong with this Macro variable &&set%eval(&i+1)

While you have received several valid suggestions, let me give you an easier approach that is less prone to errors.  Consider creating a list of all the data set names:

 

%let data_list = cards commute demossubmit financial gadgets other pets political response tele;

 

You will still need to consider how to create the initial data set JOIN1.  That is not addressed in your original macro, so I didn't try to address it here either.

 

It would be easy to loop through the list to get the joins that you want:

 

%macro join;

%local i current_set next_set;
%do i=1 %to %sysfunc(countw(&data_list)) - 1;

%let current_set = %scan(&data_list, &i);

%let next_set = %scan(&data_list, &i+1);
proc sql;
create table join%eval(&i+1) as
select *
from join&i
full join
&next_set
on join&i..custid=&next_set..custid;
quit;
%end;
%mend;

Solution
‎02-16-2016 11:34 PM
Super User
Super User
Posts: 6,844

Re: What's wrong with this Macro variable &&set%eval(&i+1)

[ Edited ]

You are confusing the macro processor by trying to generate a variable name on the fly with a macro function.  Basically the parser is seeing a hard token break between "set" and "%eval".  Just add an extra step. For example:

 

%let set2=yes;
%let i=1 ;

%put This fails: &&set%eval(&i+1);

%let varname=set%eval(&i+1);
%put This works: &&&varname ;

%let j=%eval(&i+1);
%put This also works: &&set&j ;

PROC Star
Posts: 1,291

Re: What's wrong with this Macro variable &&set%eval(&i+1)

Agree with @Tom's explanation of the problem.  Using the double ampersand method to create an indirect macro variable reference does not allow you to use a macro function to construct part of the macro reference.  The macro reference will end when the % sign is encountered.

 

As a thought exercise, with some quoting ugliness you can force an additional resolution pass after the macro function has executed, e.g.:

%let set2 = yes ;
%let i = 1 ;
%put This works: %unquote(%nrstr(&set)%eval(&i+1)) ;

 

So %nrstr() hides the & until after %eval has executed, then the whole thing is unquoted to evaluate &set2.  But I think Tom's other suggestions are more readable.

 

As this question comes up frequently, I thought I would look for a reference in the documentation that would explain this.  The best I could find in the macro language documentation on referencing macro variables indirectly is a simple note at the end: "Note: A macro call cannot be part of the resolution during indirect macro variable referencing. "

 

I wonder if there is somewhere else in the documentation that describes macro token parsing more thoroughly, which might address this question?

☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 11 replies
  • 651 views
  • 10 likes
  • 9 in conversation