The answer you arrived at (20&an
) is correct - you are all set. You don't even need to read the rest of this answer I've posted :-)
However I noticed you were a bit confused about &
vs. &&
. If you'd like to know more about that, I put together some extra info on the difference between &
and &&
, as well as the purpose of &&
, in SAS macro evaluation.
The &
is the most common symbol - you simply use that to evaluate/de-reference a variable. So:
%LET an = 14 ;
%PUT ----- an ;
%PUT ----- &an ;
Output:
----- an
----- 14
So as you can see, you must put a &
before the variable name in order to de-reference it to its value. Omitting the &
simply prints the string an
, which happens to be the name of the variable in this case. For most macro coding, &
is all you will ever need. &
in SAS macro is like $
in shell, *
in C, etc.
Now, what is &&
for? It exists to enable you to have dynamic macro variable names. That is, having a macro variable whose value is the name of another macro variable. If you are familiar with C, you can think of this as a pointer to a pointer.
The way SAS evaluates &&
is in two passes. In the first pass, it converts &&
to &
. At the same time, any &
symbols it sees in that pass will be used to de-reference the variable names they are next to. The idea is for these latter expressions to resolve to a variable name. Then, in the second pass, the remaining &
symbols (all originally &&
symbols) de-reference whatever variable names they now find themselves next to.
Here is an example with sample output:
%LET x = 3;
%LET name_of_variable = x;
%PUT ----- &x;
%PUT ----- &&name_of_variable;
%PUT ----- &&&name_of_variable;
Output:
----- 3
----- x
----- 3
In the first %PUT
, we are just using plain old &
, and thus we are doing what we did before, reading and printing the value that x
holds. In the second %PUT
, things get slightly more interesting. Because of the &&
, SAS does two passes of evaluation. The first one converts this:
%PUT ----- &&name_of_variable;
To this
%PUT ----- &name_of_variable;
In the second pass, SAS does the standard &
evaluation to print the value held in name_of_variable
- the string x
, which happens to be the name of the other variable we are using. Of course, this example is especially contrived: why would you write &&name_of_variable
when you could have just written &name_of_variable
?
In the third %PUT
, where we now have the &&&
, SAS does two passes. Here is where we finally see the true purpose of &&
. I will put pieces of the expression in parentheses so you can see how they are evaluated. We go from this:
%PUT ----- (&&)(&name_of_variable);
To this:
%PUT ----- &x;
So the in the first pass, the &&
was converted to &
, and &name_of_variable
was a simple de-referencing of name_of_variable
, evaluating to the content it is holding, which as we said was x
.
So in the second pass, we are just left with the simple evaluation:
%PUT ----- &x;
As we had set x
equal to 3, this evaluates to 3.
So in a sense, saying &&&name_of_variable
is saying "Show me the value of the variable whose name is stored in name_of_variable.
"
Here is a motivating example for why you would want to do this. Suppose you had a simple macro subroutine that added an arbitrary number to a numerical value stored in a SAS macro variable. To do that, the subroutine would have to know the amount to add, but more importantly, it would need to know the name of the variable to add to. You would accomplish this dynamic variable naming via the &&
mechanism, like so:
%MACRO increment_by_amount (var_name = , amount = );
%LET &var_name = %EVAL (&&&var_name + &amount) ;
/* Note: this could also begin with %LET &&var_name = .... */
%MEND;
Here we are saying: "Let the variable whose name is held in var_name
(i.e. &var_name
) equal the value of the variable whose name is held in var_name
(i.e. &&&var_name
) plus the value held in amount
(i.e. &amount
).
When you call a subroutine like this, make sure you are passing the variable name, not the value. That is, say this:
%increment_by_amount (var_name = x , amount = 3 );
Not this:
%increment_by_amount (var_name = &x , amount = 3);
So an example of invocation would be:
%LET x = 3;
%PUT ----- &x;
%increment_by_amount (var_name = x , amount = 3 );
%PUT ----- &x;
Output:
----- 3
----- 6