BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
svh
Lapis Lazuli | Level 10 svh
Lapis Lazuli | Level 10

I am writing a macro program in which I want to be able to call the grand mean of a variable to use as a reference line. (In my example code here, I'm using a statement that will go into the macro, which will be called by CALL EXECUTE in order to make multiple charts.)

 

%let analysisvar = MPG_City;

proc sql ;
   select mean(&analysisvar) into :M_&&analysisvar
   from sashelp.cars;
   quit;

%put &M_&ANALYSISVAR; /*This does NOT resolve to the mean.*/

%put &&M_&ANALYSISVAR; /*This DOES resolve to the mean but why?*/

 

I thought what is happening is that the PROC SQL statement is creating a macro variable &M_&AnalysisVar, but that does not appear to be the case. 

I would have expected %put &M_&AnalysisVar to resolve to the actual mean, but instead it resolves to &M_MPG_City. I'm trying to wrap my mind around why &&M_AnalysisVar resolves to the numeric value I want. I was wondering if someone knew the steps in which the ampersands are being resolved in PROC SQL in this way of assigning a value to a macro. 

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Just pretend you are the macro processor.  Your whole reason for living is to hunt out % and & and replace text with other text.  So let's step through your program.  

The macro processors ears perk up right on the first character, %, so it checks out that text and discovers a %LET statement.  It stores the text MPG_City into the macro variable analysisvar (creating analysisvar if it did not already exist) but emits NO text from that statement.

 

Next it sees some text with an &. It emits the text up until the &.

proc sql ;
   select mean(

and checks out want follows the &.  It sees a string that looks like the name of macro variable it knows about so it replaces &analysisvar with MPG_City and emits that text to SAS.

MPG_City

Then it seems more text followed by & so it emits that text.

) into :M_

And starts to check out what it sees.  I sees two & next to each other so it replaces them with a single & and reminds itself it needs check this string out again when it reaches the end. 

Then it sees more text followed by a space (or end of line) so it knows it has hit the end of the token which is now &analysisvar which it replaces with MPG_City and emits.

MPG_City

The it  sees more text until there is a % so it emits that text.

   from sashelp.cars;
   quit;

At this point SAS has seen the whole SQL step and has run it.

 

The macro processor then recognizes the %PUT statement and so starts checking out what you want it to write to the LOG.

It then sees & and starts checking if this is a macro variable reference.  But instead if just finds the token &M_ so it issues a warning that it doesn't know anything about this M_ macro variable and writes the &M_ to the log.

Then is sees & and this time recognizes our old friend and writes its value to the log.

 

For the second %PUT statement when it sees the double & it again replaces them with  a single & and reminds itself to re-review this token when it gets to the end.  It then sees the plain text M_ and remembers it.  Then it sees the reference to our old friend analysisvar again and replaces it.  Then it reaches the ; so it knows it has reached the end the token and rescans what it has which is now &M_MPG_City.  This looks like a reference to a macro variable, and it should be found since the SQL code that it just gave to SAS to run created it. So the %PUT statement writes the value of M_MPG_City to the log.

 

 

View solution in original post

5 REPLIES 5
ballardw
Super User

Indirect referencing, with the multiple &&&&& type calls is basically the leftmost & (or multiples) hold off resolving until the ones to the right resolve.

 

The question is why did you use the

 into :M_&&analysisvar

in the first place

When I run your code the log shows:

11   %let analysisvar = MPG_City;
12
13   proc sql ;
14      select mean(&analysisvar) into :M_&&analysisvar
15      from sashelp.cars;
16      quit;
NOTE: PROCEDURE SQL used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


WARNING: Apparent symbolic reference M_ not resolved.
18 %put &M_&ANALYSISVAR; /*This does NOT resolve to the mean.*/
&M_MPG_City

That particular warning basically means you have attempted to use a macro variable that doesn't exist, which is why it shows the &M_MPG_City in the log. You have implied that you have two macro variables, M_ and Analysisvar.

 

When you use the

put &&M_&ANALYSISVAR;

The first & holds off resolving and generates the equivalent of &M_MPG_CITY, which is the macro variable created.

 

You can see which macro variables you have defined currently in the scope you execute it with and their value by using

%put _user_;

 

svh
Lapis Lazuli | Level 10 svh
Lapis Lazuli | Level 10
I used
into :M_&&analysisvar because I'm writing a program in which
&analysisvar is a macro variable in a larger program, with steps before
this one. Thus, I'd like to use the same macro variable to make the summary
statistics I need for charts (rather than try to use another one for this
step). After some trial and error, I learned I needed :M_&&analysisvar to
be in the SELECT statement. It's a happy accident, but I sometimes don't
fully understand how these are resolved. Thanks for your help.



Tom
Super User Tom
Super User

To reference a macro variable you only need one &.  The happy accident is that using two also worked.

 

Using  the SYMBOLGEN option can help you see what is happening.

337   %let analysisvar=MPG_City;
338
339   options symbolgen;
340   %put M_&analysisvar ;
SYMBOLGEN:  Macro variable ANALYSISVAR resolves to MPG_City
M_MPG_City
341   %put M_&&analysisvar ;
SYMBOLGEN:  && resolves to &.
SYMBOLGEN:  Macro variable ANALYSISVAR resolves to MPG_City
M_MPG_City
Cynthia_sas
SAS Super FREQ
Hi:
Take a look at pages 10-11 and Figure 18 in this paper https://support.sas.com/resources/papers/proceedings13/120-2013.pdf . The Figure is an example of Macro Variable "indirect reference". This may help you understand more about how macro variables can be resolved.
Cynthia
Tom
Super User Tom
Super User

Just pretend you are the macro processor.  Your whole reason for living is to hunt out % and & and replace text with other text.  So let's step through your program.  

The macro processors ears perk up right on the first character, %, so it checks out that text and discovers a %LET statement.  It stores the text MPG_City into the macro variable analysisvar (creating analysisvar if it did not already exist) but emits NO text from that statement.

 

Next it sees some text with an &. It emits the text up until the &.

proc sql ;
   select mean(

and checks out want follows the &.  It sees a string that looks like the name of macro variable it knows about so it replaces &analysisvar with MPG_City and emits that text to SAS.

MPG_City

Then it seems more text followed by & so it emits that text.

) into :M_

And starts to check out what it sees.  I sees two & next to each other so it replaces them with a single & and reminds itself it needs check this string out again when it reaches the end. 

Then it sees more text followed by a space (or end of line) so it knows it has hit the end of the token which is now &analysisvar which it replaces with MPG_City and emits.

MPG_City

The it  sees more text until there is a % so it emits that text.

   from sashelp.cars;
   quit;

At this point SAS has seen the whole SQL step and has run it.

 

The macro processor then recognizes the %PUT statement and so starts checking out what you want it to write to the LOG.

It then sees & and starts checking if this is a macro variable reference.  But instead if just finds the token &M_ so it issues a warning that it doesn't know anything about this M_ macro variable and writes the &M_ to the log.

Then is sees & and this time recognizes our old friend and writes its value to the log.

 

For the second %PUT statement when it sees the double & it again replaces them with  a single & and reminds itself to re-review this token when it gets to the end.  It then sees the plain text M_ and remembers it.  Then it sees the reference to our old friend analysisvar again and replaces it.  Then it reaches the ; so it knows it has reached the end the token and rescans what it has which is now &M_MPG_City.  This looks like a reference to a macro variable, and it should be found since the SQL code that it just gave to SAS to run created it. So the %PUT statement writes the value of M_MPG_City to the log.

 

 

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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
  • 5 replies
  • 522 views
  • 1 like
  • 4 in conversation