DATA Step, Macro, Functions and more

Macro logical %if fails when comparing macro variables to data step variabl

Reply
Occasional Contributor
Posts: 17

Macro logical %if fails when comparing macro variables to data step variabl

Hi, SAS-Lers,
I have a macro that uses a %if statement to check the value of a macro variable against a *data step* variable. The problem is that the comparison seems to check the value of the macro variable (which resolves correctly) to the *name* of the data set variable (qnum in this case). Any ideas here ? I tried several approaches using call symput, call execute, %eval, - all without success.
Here is version 1 of the program:
option symbolgen mprint mlogic;

data one;
input qnum;
datalines;
1
2
3
;

proc print data = one;
title 'Test data set';
run;


%macro makevar;
%local x;
data new;
set one;
%do x = 1 %to 3;
%if &x=qunum %then %do; /* Should be TRUE for first obs of data set */
%put IF condition is true for &i ;
%end;
%end;
run;
%mend makevar;

%makevar

Part of the log for this program :
28 %makevar
MLOGIC(MAKEVAR): Beginning execution.
MLOGIC(MAKEVAR): %LOCAL X
MPRINT(MAKEVAR): data new;
MPRINT(MAKEVAR): set one;
MLOGIC(MAKEVAR): %DO loop beginning; index variable X; start value is 1; stop value is 3; by value is 1.
SYMBOLGEN: Macro variable X resolves to 1
MLOGIC(MAKEVAR): %IF condition &x=qunum is FALSE <-- HERE IS THE PROBLEM
MLOGIC(MAKEVAR): %DO loop index variable X is now 2; loop will iterate again.
SYMBOLGEN: Macro variable X resolves to 2
MLOGIC(MAKEVAR): %IF condition &x=qunum is FALSE
MLOGIC(MAKEVAR): %DO loop index variable X is now 3; loop will iterate again.
SYMBOLGEN: Macro variable X resolves to 3
MLOGIC(MAKEVAR): %IF condition &x=qunum is FALSE
MLOGIC(MAKEVAR): %DO loop index variable X is now 4; loop will not iterate again.
MPRINT(MAKEVAR): run;

So, it appears the comparison %if is making is the resolved value of &x (which is 1) to the name 'qnum'; hence, it is never true - and it should be on the first observation of the data set.

Second try using call symput and second macro variables &y:
%macro makevar;
%local x y;
data new;
set one;
%do x = 1 %to 3;
call symputx('y',qnum);
%if &x=&y %then %do; /* Should be TRUE for first obs of data set */
%put IF condition is true for &x ;
%end;
%end;
run;
%mend makevar;

%makevar

And here's the log from this program:
29 %makevar
MLOGIC(MAKEVAR): Beginning execution.
MLOGIC(MAKEVAR): %LOCAL X Y
MPRINT(MAKEVAR): data new;
MPRINT(MAKEVAR): set one;
MLOGIC(MAKEVAR): %DO loop beginning; index variable X; start value is 1; stop value is 3; by value is 1.
MPRINT(MAKEVAR): call symputx('y',qnum);
SYMBOLGEN: Macro variable X resolves to 1
SYMBOLGEN: Macro variable Y resolves to <-- HERE IS THE PROBLEM
MLOGIC(MAKEVAR): %IF condition &x=&y is FALSE
MLOGIC(MAKEVAR): %DO loop index variable X is now 2; loop will iterate again.
MPRINT(MAKEVAR): call symputx('y',qnum);
SYMBOLGEN: Macro variable X resolves to 2
SYMBOLGEN: Macro variable Y resolves to
MLOGIC(MAKEVAR): %IF condition &x=&y is FALSE
MLOGIC(MAKEVAR): %DO loop index variable X is now 3; loop will iterate again.
MPRINT(MAKEVAR): call symputx('y',qnum);
SYMBOLGEN: Macro variable X resolves to 3
SYMBOLGEN: Macro variable Y resolves to
MLOGIC(MAKEVAR): %IF condition &x=&y is FALSE
MLOGIC(MAKEVAR): %DO loop index variable X is now 4; loop will not iterate again.
MPRINT(MAKEVAR): run;


Do any of you macro experts have any idea why this is not working ? I have a feeling it involves the timing of the macro compilation vs. data set compilation.

Barry Walton
Barry.Walton@millersville.edu
Super Contributor
Super Contributor
Posts: 3,174

Re: Macro logical %if fails when comparing macro variables to data step variabl

You are attempting to mix SAS macro language (code and macro variable resolution) with SAS DATA step execution logic - the two are complementary however they cannot be interwoven, normally.

The macro logic / execution is resolved at SAS compilation time, evident when you have coded the following SAS OPTIONS statement for the most diagnostic output:

OPTIONS SOURCE SOURCE2 MACROGEN SYMBOLGEN MLOGIC MPRINT;

So, you will need/want to consider this challenge when developing your SAS application program/solution.

Scott Barry
SBBWorks, Inc.
Super Contributor
Super Contributor
Posts: 365

Re: Macro logical %if fails when comparing macro variables to data step variabl

Hello Enginemane44,

This is a solution. Simply replace %IF with datastep if:

%macro makevar;
%local x;
data new;
set one;
%do x = 1 %to 3;
data new;
set one;
if &x = qnum then do; /* Should be TRUE for first obs of data set */
%put IF condition is true for &x ;
end;
run;

%end;
%mend makevar;

%makevar

Sincerely,
SPR
Regular Contributor
Posts: 171

Re: Macro logical %if fails when comparing macro variables to data step variabl

In your code, because the %put statement is a macro statement, it will be executed whether or not the condition &x=qnum (specified in the data step if statement) is true. As sbb pointed out, you are still mixing macro logic with data step logic. To see this, change the condition to “if 1 = 2” and watch what happens:
[pre]

MPRINT(MAKEVAR): data new;
MPRINT(MAKEVAR): set one;
MPRINT(MAKEVAR): if 1 = 2 then do;
MLOGIC(MAKEVAR): %PUT IF condition is true for &x
IF condition is true for 1
MPRINT(MAKEVAR): end;
MPRINT(MAKEVAR): run;

NOTE: There were 3 observations read from the data set WORK.ONE.
NOTE: The data set WORK.NEW has 3 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds


MLOGIC(MAKEVAR): %DO loop index variable X is now 2; loop will iterate again.
MPRINT(MAKEVAR): data new;
MPRINT(MAKEVAR): set one;
MPRINT(MAKEVAR): if 1 = 2 then do;
MLOGIC(MAKEVAR): %PUT IF condition is true for &x
IF condition is true for 2
MPRINT(MAKEVAR): end;
MPRINT(MAKEVAR): run;

NOTE: There were 3 observations read from the data set WORK.ONE.
NOTE: The data set WORK.NEW has 3 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds


MLOGIC(MAKEVAR): %DO loop index variable X is now 3; loop will iterate again.
MPRINT(MAKEVAR): data new;
MPRINT(MAKEVAR): set one;
MPRINT(MAKEVAR): if 1 = 2 then do;
MLOGIC(MAKEVAR): %PUT IF condition is true for &x
IF condition is true for 3
MPRINT(MAKEVAR): end;
MPRINT(MAKEVAR): run;

NOTE: There were 3 observations read from the data set WORK.ONE.
NOTE: The data set WORK.NEW has 3 observations and 1 variables.
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.00 seconds


MLOGIC(MAKEVAR): %DO loop index variable X is now 4; loop will not iterate again.
MLOGIC(MAKEVAR): Ending execution.

[/pre]


Here is an alternative which reads only one observation from the dataset, using call symput to create a corresponding macro variable, and then performs the macro logic after the data step has finished executing:
[pre]
data one;
input qnum;
datalines;
1
2
3
5
;

%macro makevar;

%local x DSID NOBS DSIDC;

/*** OBTAIN NUMBER OF OBSERVATIONS ***/
%LET DSID=%SYSFUNC(OPEN(ONE));
%LET NOBS=%SYSFUNC(ATTRN(&DSID,NLOBS));
%LET DSIDC=%SYSFUNC(CLOSE(&DSID));

%DO X=1 %TO &NOBS;
data _NULL_;
OBNUM=&X;
set one POINT=OBNUM;
CALL SYMPUTX("QNUM", QNUM);
STOP;
RUN;
%if &x=&qnum %then %do; /* Should be TRUE for first obs of data set */
%put IF condition is true for &X ;
%end;
%else %do;
%put IF condition is not true for &X.. QNUM = &QNUM;
%end;
%end;

%mend makevar;
%MAKEVAR
[/pre]
Super Contributor
Super Contributor
Posts: 365

Re: Macro logical %if fails when comparing macro variables to data step variabl

It does not matter. The condition (if &x = qnum then doSmiley Wink works correctly. To test it simply replace

%put IF condition is true for &x ;

with

put qnum= "IF condition is true for &x" ;

SPR
Regular Contributor
Posts: 171

Re: Macro logical %if fails when comparing macro variables to data step variabl

Yes, if you use a put statement instead of %put, the program will work. I was just pointing out that you cannot use a data step if statement to conditionally execute a %put macro statement.

The example I previously posted above was to illustrate a macro that “uses a %if statement to check the value of a macro variable against a data step variable.” However, it sounds like the %if statement is not needed in this example at all.
Occasional Contributor
Posts: 17

Re: Macro logical %if fails when comparing macro variables to data step variabl

Hello all,

SPR's suggestion to change the %if to a regular if did the job ! Thank you for the help !
One general question - can someone direct me to some online info/papers that deal with this topic ? I took the 'SAS Macro Language 2' course in June, but we didn't go into this topic in detail (it was still a worthwhile course). I've searched various archives, but couldn't come up with very much.
Again, thanks to SPR - your solution worked.

Barry Walton
Barry.Walton@millersville.edu
Super Contributor
Super Contributor
Posts: 365

Re: Macro logical %if fails when comparing macro variables to data step variabl

Hello Enginemane44,

As far as I know, the problem in your program is because %if condition is resolved on compilation stage when variable values are not accessible yet.

This is an extraction from SAS help topic "%IF-%THEN/%ELSE Statement":

Comparisons


Although they look similar, the %IF-%THEN/%ELSE statement and the IF-THEN/ELSE statement belong to two different languages. In general, %IF-%THEN/%ELSE statement, which is part of the SAS macro language, conditionally generates text. However, the IF-THEN/ELSE statement, which is part of the SAS language, conditionally executes SAS statements during DATA step execution.

The expression that is the condition for the %IF-%THEN/%ELSE statement can contain only operands that are constant text or text expressions that generate text. However, the expression that is the condition for the IF-THEN/ELSE statement can contain only operands that are DATA step variables, character constants, numeric constants, or date and time constants.

When the %IF-%THEN/%ELSE statement generates text that is part of a DATA step, it is compiled by the DATA step compiler and executed. On the other hand, when the IF-THEN/ELSE statement executes in a DATA step, any text generated by the macro facility has been resolved, tokenized, and compiled. No macro language elements exist in the compiled code. "Example 1: Contrasting the %IF-%THEN/%ELSE Statement with the IF-THEN/ELSE Statement" illustrates this difference.

For more information, see SAS Programs and Macro Processing, and Macro Expressions.

Sincerely,
SPR
Ask a Question
Discussion stats
  • 7 replies
  • 204 views
  • 0 likes
  • 4 in conversation