for example: Step1: %let tab=3; %macro test(); %if 1<&tab.<4 %then %do; %put it worked; %end; %mend test; %test; Step2: when i modified "%let tab =4; it still prints "it worked".
In the language of normal SAS code you can abbreviate an expression in the form:
(A op1 B) and (B op2 C)
By removing the AND and the duplicate value/variable to get:
A op1 B op2 C
But the language used by the MACRO PROCESSOR does NOT support that abbreviated syntax.
If you have a question about how to expand an abbreviated expression you can use it in a WHERE statement and SAS will echo to restructured syntax in the log.
1 data want; 2 set sashelp.class; 3 where age < height < weight ; 4 run; NOTE: There were 18 observations read from the data set SASHELP.CLASS. WHERE (age<height) and (height<weight); NOTE: The data set WORK.WANT has 18 observations and 5 variables. NOTE: DATA statement used (Total process time): real time 0.07 seconds cpu time 0.01 seconds
I couldn't find it in the documentation but using macro language you can't combine comparison operators the way you did.
Below syntax will return what you're after.
%macro test(tab);
/* %if %eval(1<&tab.<4) %then*/
%if 1<&tab. and &tab.<4 %then
%do;
%put TRUE;
%end;
%else %put FALSE;
%mend test;
%test(3);
%test(4);
Unlike the IF clause in regular SAS data step, the %IF macro statement processes from left to right, which means the expression
%IF 1<&tab.<4
first evaluates the 1<&tab component. When macrovar &TAB equals 3, this component resolves to 1 (for true). When macrovar &TAB is, say 0, this component resolves to 0 (for false).
Then it tests whether that resolved value is less than 4, which is also true (because both 0 and 1 are <4). In fact, for any &TAB value, the %IF 1<&tab.<4 macro test will always be true.
But as you no doubt know, this is NOT the behavior of the non-macro IF statement, which imputes an implicit AND operator when you have the if value1 relop value2 relop value3 structure (where "relop" means relational operator). So the expression
if 1<%tab.<4
is interpreted as
if 1<&tab. AND &tab<4
@Bill3 wrote:
It seems quite reasonable. So there's no way to combine these two relop in %if?
I believe you will have to insert the AND operator, as in:
%if 1<&tab. AND &tab.<4 %then %do;
In the language of normal SAS code you can abbreviate an expression in the form:
(A op1 B) and (B op2 C)
By removing the AND and the duplicate value/variable to get:
A op1 B op2 C
But the language used by the MACRO PROCESSOR does NOT support that abbreviated syntax.
If you have a question about how to expand an abbreviated expression you can use it in a WHERE statement and SAS will echo to restructured syntax in the log.
1 data want; 2 set sashelp.class; 3 where age < height < weight ; 4 run; NOTE: There were 18 observations read from the data set SASHELP.CLASS. WHERE (age<height) and (height<weight); NOTE: The data set WORK.WANT has 18 observations and 5 variables. NOTE: DATA statement used (Total process time): real time 0.07 seconds cpu time 0.01 seconds
@Bill3 wrote:
for example: Step1: %let tab=3; %macro test(); %if 1<&tab.<4 %then %do; %put it worked; %end; %mend test; %test; Step2: when i modified "%let tab =4; it still prints "it worked".
A couple of tests make me think that the way the SAS Macro processor handles something like 1<3<4 is that it first, left to right, resolves the first comparison: 1<3. Which may return 0 for False or 1 for true. Then uses that result in the <4. So pretty much regardless what the first comparison would be the result is 1 because both 1 and 0 are less than 4.
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
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.
Ready to level-up your skills? Choose your own adventure.