2

I have a SAS project (EGv7.1) that allows the user to specify a value on the first line. Then, other processes are invoked based on the value specified. One of these is that some other macro variables are assigned. Below is what I have, and it does not seem to be working. I really need the let statement to be first in the sequence, but besides that I am open to changes. Any suggestions?

%let number=8;

%macro my_function();
    %if &number=8 %then 
        %do;
            %let number_text=eight;
            %let number_text_2=equal to eight;
        %end;
    %if &number>8 %then
            %do;
            %let number_text=not eight;
            %let number_text_2=greater then eight;
        %end;
    %if &number<8 %then
            %do;
            %let number_text=not eight;
            %let number_text_2=less than eight;
        %end;
%mend my_function;
%my_function();

%put =================&number==================;
%put ===========The number is &number_text.=============;
%put =======Furthermore, the number is &number_text_2.========;
2
  • 2
    Although your program is probably more complex than the above, if you're using prompts (as you should if you're in EG!) you can do some of this via the prompt interface rather than bothering with macros. Commented Jan 8, 2015 at 16:49
  • Yes, I agree that prompts would be the better way to go here. I've been testing the prompt manager functionality, but need a short term solution. Thanks for the suggestion, though. Commented Jan 8, 2015 at 17:18

2 Answers 2

3

When you use %let statements inside of a macro, the variables default to local scope. That is, they only exist inside the macro. To remedy that add a %global statement inside the macro.

%let number = 8;

%macro my_function();
    %global number_text number_text_2;

    %if %sysevalf(&number = 8) %then 
        %do;
            %let number_text = eight;
            %let number_text_2 = equal to eight;
        %end;
    %else %if %sysevalf(&number > 8) %then
        %do;
            %let number_text = not eight;
            %let number_text_2 = greater than eight;
        %end;
    %else %if %sysevalf(&number < 8) %then
        %do;
            %let number_text = not eight;
            %let number_text_2 = less than eight;
        %end;

%mend my_function;
%my_function();

This tells SAS that the macro variables number_text and number_text_2 should be accessible outside of the macro, which should fix your problem.

I also recommend adding %else to your %ifs. This ensures that each condition is only evaluated if the one preceding it is false. Without %else, each condition is evaluated every time.

As @DomPazz mentioned, it's a good idea to use %sysevalf() when evaluating numeric conditions.

Sign up to request clarification or add additional context in comments.

6 Comments

This is correct. Scoping of macro variables is a little more complex than described here. I highly recommend reading the documentation on it: support.sas.com/documentation/cdl/en/mcrolref/68140/HTML/…
@DomPazz: Agreed, scoping is more complex than I described. It would have been more accurate to say that adding %global means that it will be accessible in (nearly) all places in the program, including open code and any nested macros, for the duration of the session unless explicitly deleted.
I wouldn't use %else if because of efficiency - this will run once, in a few microseconds. I would use %else if because it makes it more clear that it will only pass through one of the three paths, and not potentially more than one.
One change I would make to this answer. Enclose the logical tests with %sysevalf(), i.e. %if %sysevalf(&number < 8).... The tests as written will be done via string compares, not numbers. This can, and often does, cause heartaches!
@DomPazz: Feel free to edit my answer as you see fit. I edited it to include your recommendation of %sysevalf().
|
1

If you're not passing in any values why use a macro at all? Here's a way to do it using a data null step.

%let number=3;

data _null_;
if &number=8 then do;
call symputx('number_text_3', "eight", g);
call symputx('number_text_4', "equal to eight", g);
end;
else if &number>8 then do;
call symputx('number_text_3', "not eight", g);
call symputx('number_text_4', "greater than eight", g);
end;
else if &number<8 then do;
call symputx('number_text_3', "not eight", g);
call symputx('number_text_4', "less than eight", g);
end;

run;

%put &number_text_3;
%put &number_text_4;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.