2
votes

I have a macro in SAS that is not working correctly. I have a %goto statement that is triggered if a macro variable's value is larger than some fixed number. The macro variable is created by the following sample code;

proc sql noprint;
select num into :num
from table;
quit;

When opening up the table, the num variable has the number in standard notation (e.g. 645,435,243). However, the macro variable &num. picks it up as 6.4544E8. This causes an issue then when SAS attempts to compare this value to a number such as 1,000,000.

I was able to recreate this issue with the simple macro below, the only difference is in the way the macro variable is assigned the value. In the code below, I assign j 1E8 directly rather than through a proc sql statement.

My question is this: why is SAS unable to evaluate 1E8 > 5 correctly?

%macro test();

%let i = 1;
%let j = 1E8;

data test0;
x = &i.;
output;
run;

%let i = 2;

%do %until (&i. = 11);

%put &i.;

%if &i. >= 7 %then %do;
    %if &j. > 5 %then %do;
        %goto done;
    %end;
%end;

data test&i.;
x = &i.;
output;
run;

proc append base=test0 data=test&i.;
run;

proc datasets library=work nolist;
delete test&i.;
run;

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

%end;

%done: %mend;

%test();
1
SAS macro variables are just text. SAS macros just generate more text.david25272

1 Answers

2
votes

Because %if &j > 5 is not performing a "mathematical" comparison, but effectively a text comparison. Regular old %eval will only do integer math, and comparisons are basically just comparing the two things as text. SAS macro variables are almost always treated as text, not anything else, and so always, always use %sysevalf if you want SAS to first treat them as numbers - or use regular data step variables.

You need to use %sysevalf if you want SAS to treat macro variable contents as real numbers.

%if &i. >= 7 %then %do;
    %if %sysevalf(&j. > 5,boolean) %then %do;
        %goto done;
    %end;
%end;

Note that if you had chosen %let j = 7E8;, it would've appeared to work - because it's only comparing 5 to 7 and that's true.

Even better, %let J = 5E8; would be greater - since E is greater than nothing - but if you compared &j > 5A it would still work, while &j > 5F it would not work. There it's comparing E (the letter) to F (the letter) and finds F is bigger.