BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
MeganE
Pyrite | Level 9

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

1 ACCEPTED SOLUTION

Accepted Solutions
Astounding
PROC Star

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

7 REPLIES 7
RW9
Diamond | Level 26 RW9
Diamond | Level 26

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.  

MeganE
Pyrite | Level 9

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.

Reeza
Super User

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 

RW9
Diamond | Level 26 RW9
Diamond | Level 26

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;
MeganE
Pyrite | Level 9

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.

RW9
Diamond | Level 26 RW9
Diamond | Level 26

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.

Astounding
PROC Star

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.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

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