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.
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.