DATA Step, Macro, Functions and more

macro var not resolving properly within %if/%then

Accepted Solution Solved
Reply
Frequent Contributor
Posts: 128
Accepted Solution

macro var not resolving properly within %if/%then

Hello,

 

I have this code:

%macro merge();

%if 2003 <= &year. < 2006 %then %do;

      data junk.allclaims_&year.;

            set junk.op_&year.

                  junk.hh_&year.

                  junk.hs_&year.

                  junk.sn_&year.

                  clms.ip_&year. (drop=mod1 dm)

                  junk.ps_&year.;

            format hcfasaf $claimf.;

            where payamt>0;

      run;

%end;

%if &year. >= 2006 %then %do;

      data junk.allclaims_&year.;

            set junk.op_&year.

                  junk.hh_&year.

                  junk.hs_&year.

                  junk.sn_&year.

                  clms.ip_&year. (drop=mod1 dm)

                  junk.ps_&year.

                  junk.partd_&year.;

            format hcfasaf $claimf.;

            where payamt>0;

      run;

%end;

%mend merge;

 

 

I ran it for year=2014, and SAS evaluated it as true for both.  So it basically ran twice.  What do I need to change to make this work correctly?

 

Relevent parts from the log:

 

SYMBOLGEN:  Macro variable YEAR resolves to 2014

MLOGIC(MERGE):  %IF condition 2003 <= &year. < 2006 is TRUE

    

 

SYMBOLGEN:  Macro variable YEAR resolves to 2014

MLOGIC(MERGE):  %IF condition &year. >= 2006 is TRUE

 

Thanks,

Megan


Accepted Solutions
Solution
‎06-23-2016 10:11 AM
Super User
Posts: 5,085

Re: macro var not resolving properly within %if/%then

[ Edited ]

First, note that your original question has been answered.  Unlike in a DATA step, this comparison evaluates from left to right in macro language:

 

%if 2003 <= &year. < 2006 %then %do;

 

Depending on the value of &Year, it becomes one of the following:

 

%if 0 < 2006 %then %do;

%if 1 < 2006 %then %do;

 

So the compound condition is always true.  Splitting the comparison would work, but isn't the best solution in this particular case:

 

%if (2003 <= &year) and (&year < 2006) %then %do;

 

Since most of the code is identical regardless of &YEAR, a better solution would take advantage of that:

 

 

%macro merge();

%if 2003 <= &year. %then %do;

      data junk.allclaims_&year.;

            set junk.op_&year.

                  junk.hh_&year.

                  junk.hs_&year.

                  junk.sn_&year.

                  clms.ip_&year. (drop=mod1 dm)

                  junk.ps_&year.

                  %if &year. >= 2006 %then junk.partd_&year.;

                  ;

            format hcfasaf $claimf.;

            where payamt>0;

      run;

%end;

%mend merge;

 

You can still add the extra DATA set when needed.  But it becomes obvious that the rest of the code is identical, and becomes easier to maintain if there are future changes to make.

 

Good luck.

 

*****************************************

 

Sorry, RW9.  Looks like you posted almost the same answer while I was working on mine.

View solution in original post


All Replies
Super User
Super User
Posts: 7,407

Re: macro var not resolving properly within %if/%then

Macro language is text based, so your comparing a string of characters from the &year macro variable - all macro variables are character - with 2006 which is a number.  

However some questions.  First why call the macro merge - it is setting data together not merging.  Secondly why the macro code at all?  Both the datasteps are exactly the same.  Macro language is Not a replacement for Base SAS it is only there to save you typing things multiple times.  

Frequent Contributor
Posts: 128

Re: macro var not resolving properly within %if/%then

It's called merge because i didn't name it, lol.  It's inherited code.  But they're not the same.  The one for > 2006 has an extra dataset at the end.

 

So how can i get a macro variable to be treated like a number?  While it's not a lot of work to add a new year every year, i'm afraid we're going waste time forgetting to add it, run it as is, and have to go back and re-do it.  The code isn't short.  This part is buried down near the end.

Super User
Posts: 17,842

Re: macro var not resolving properly within %if/%then

I don't think you can use the first type of comparison in a macro. You need to have two conditions with an AND instead. 

 

var <= mvar < something else 

Super User
Super User
Posts: 7,407

Re: macro var not resolving properly within %if/%then

Yes, this is common.  Macros which have been around since the dawn of time, no-one ever changes them or follows software development lifecycle practices, and the next person will just bolt more on...

 

To answer your question, you need to use %eval() like this:

%macro Merge ();
  data junk.allclaims_&year.;
    set junk.op_&year.
        junk.hh_&year.
        junk.hs_&year.
        junk.sn_&year.
        clms.ip_&year. (drop=mod1 dm)
        junk.ps_&year.
  %if %eval(&year >= 2006) %then %do;
        junk.partd_&year.
  %end;
        ;
    format hcfasaf $claimf.;
    where payamt>0;
  run;
%mend Merge;

However, I would also add, it would make your life, and other programmers life a lot easier if you didn't put data in the table names (i.e. Years in this case).  Simply put your data together and use indsname= option, then you only have one dataset to worry about:

data want;
  length bygroup $2000;
  set  <datasets> indsname=tmp;
  by group=indsname;
run;

/* Then to get a date range */
data xyz;
  set want (where=(...));
run;
Frequent Contributor
Posts: 128

Re: macro var not resolving properly within %if/%then

Thanks for the %eval().  I'll try it.

 

I don't understand your second part though.  We have to put years so we can keep everything separate.  We're running datasets from 2003 to 2014.  I don't want them overwritten each time.

Super User
Super User
Posts: 7,407

Re: macro var not resolving properly within %if/%then

Nope, you would compile all the original datasets into one dataset, with an aditional variable which identifies the year.  That way you only need to program based on one dataset, and can still subset data based on the year variable.  Its the way databases have worked for years.

Solution
‎06-23-2016 10:11 AM
Super User
Posts: 5,085

Re: macro var not resolving properly within %if/%then

[ Edited ]

First, note that your original question has been answered.  Unlike in a DATA step, this comparison evaluates from left to right in macro language:

 

%if 2003 <= &year. < 2006 %then %do;

 

Depending on the value of &Year, it becomes one of the following:

 

%if 0 < 2006 %then %do;

%if 1 < 2006 %then %do;

 

So the compound condition is always true.  Splitting the comparison would work, but isn't the best solution in this particular case:

 

%if (2003 <= &year) and (&year < 2006) %then %do;

 

Since most of the code is identical regardless of &YEAR, a better solution would take advantage of that:

 

 

%macro merge();

%if 2003 <= &year. %then %do;

      data junk.allclaims_&year.;

            set junk.op_&year.

                  junk.hh_&year.

                  junk.hs_&year.

                  junk.sn_&year.

                  clms.ip_&year. (drop=mod1 dm)

                  junk.ps_&year.

                  %if &year. >= 2006 %then junk.partd_&year.;

                  ;

            format hcfasaf $claimf.;

            where payamt>0;

      run;

%end;

%mend merge;

 

You can still add the extra DATA set when needed.  But it becomes obvious that the rest of the code is identical, and becomes easier to maintain if there are future changes to make.

 

Good luck.

 

*****************************************

 

Sorry, RW9.  Looks like you posted almost the same answer while I was working on mine.

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 7 replies
  • 286 views
  • 0 likes
  • 4 in conversation