BookmarkSubscribeRSS Feed
TPayne
Fluorite | Level 6

Hello!

I have a dataset I want to do a series of if/then statements with a series of variables that have a prefix i've assigned to a macro value but the macro isn't cycling how it should be. I don't get any errors in the log (see below) but it only produces a result for my last macro value NER. any insight would be helpful please!

 

code:

%MACRO INTERVALS (REGION);

%LET REGION=MCR SCR NER;

%do i=1 %to %sysfunc(countw(&REGION));
%LET REGIONS= %SCAN(&REGION,&i);
%put &REGIONS;

DATA DATA.REGIONALVALUES6;
SET DATA.REGIONALVALUES5;

IF (&REGIONS._HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM) THEN &REGIONS._HIB_SIGNIFICANCE=1;

RUN;

%END;

%MEND INTERVALS;
%INTERVALS (MCR SCR NER);

 

log:

5038 %MACRO INTERVALS (REGION);
5039
5040 %LET REGION=MCR SCR NER;
5041
5042 %do i=1 %to %sysfunc(countw(&REGION));
5043 %LET REGIONS= %SCAN(&REGION,&i);
5044 %put &REGIONS;
5045
5046 DATA DATA.REGIONALVALUES6;
5047 SET DATA.REGIONALVALUES5;
5048
5049 IF (&REGIONS._HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM) THEN
5049! &REGIONS._HIB_SIGNIFICANCE=1;
5050
5051 RUN;
5052
5053 %END;
5054
5055 %MEND INTERVALS;
5056 %INTERVALS (MCR SCR NER);
MCR

NOTE: There were 1 observations read from the data set DATA.REGIONALVALUES5.
NOTE: The data set DATA.REGIONALVALUES6 has 1 observations and 758 variables.
NOTE: DATA statement used (Total process time):
real time 0.45 seconds
cpu time 0.03 seconds


SCR

NOTE: There were 1 observations read from the data set DATA.REGIONALVALUES5.
NOTE: The data set DATA.REGIONALVALUES6 has 1 observations and 758 variables.
NOTE: DATA statement used (Total process time):
real time 0.08 seconds
cpu time 0.03 seconds


NER

NOTE: There were 1 observations read from the data set DATA.REGIONALVALUES5.
NOTE: The data set DATA.REGIONALVALUES6 has 1 observations and 758 variables.
NOTE: DATA statement used (Total process time):
real time 0.06 seconds
cpu time 0.01 seconds

 

2 REPLIES 2
Quentin
Super User

Hi,

 

As shown in the log, your macro is looping appropriately.  If you turn on options MPRINT, it would allow you to see that you generate valid code for three data steps, and each executes correctly.

 

But the problem is in every data step, the output dataset is DATA.REGIONALVALUES6.  So the first step creates DATA.REGIONALVALUES6 (assuming it didn't exist already), the second step over-writes it, and the third step over-writes it.  

 

If you want to have three different output datasets, you need to have the macro generate different names for the output dataset.  For example, you could change the output dataset to be DATA.REGIONALVALUES6_&regions, so that when you call the macro, it would create DATA.REGIONALVALUES6_MCR DATA.REGIONALVALUES6_SCR and DATA.REGIONALVALUES6_NER.

The Boston Area SAS Users Group (BASUG) is hosting our in person SAS Blowout on Oct 18!
This full-day event in Cambridge, Mass features four presenters from SAS, presenting on a range of SAS 9 programming topics. Pre-registration by Oct 15 is required.
Full details and registration info at https://www.basug.org/events.
RichardDeVen
Barite | Level 11

You may not want to use macro in this situation.  If your code is dealing with UCLM and SIGNIFICANCE variables that are aught to change or be different sets of variables in a different process flow macro might be warranted.  The strongest foundation for writing macro code that generates SAS code is to be able to write clear non-macro code first.  You want to trade off the clarity of direct code versus the reusability or semantic shortening offered by implementing a macro.

 

Consider this non macro version

DATA DATA.REGIONALVALUES6;

  SET DATA.REGIONALVALUES5;

  ARRAY UCLMS
    MCR_HIB_COMPLETE_UCLM
    SCR_HIB_COMPLETE_UCLM
    NER_HIB_COMPLETE_UCLM
  ;

  ARRAY SIGS
    MCR_HIB_SIGNIFICANCE
    SCR_HIB_SIGNIFICANCE
    NER_HIB_SIGNIFICANCE
  ;

  do _n_ = 1 to dim (UCLMS);  * repurpose _n_ as loop index;
    
    if UCLMS(_N_) < STATE_HIB_COMPLETE_LCLM then SIGS(_n_) = 1;

  end;
RUN;

You might want to ask your self, if I go macro should the entire step be macroized or just the generation of the variable names listed for the array definitions.

  • If the entire step, should the input (SET) and output (DATA) data set names be hard coded, or be parameters of the macro ?
    •   If hard coded, does that offered any benefit long term ? (Probably not) 
  • Should the limit variable holding the cutoff value (STATE_HIB_COMPLETE_LCLM ) be hardcoded or a parameter ?

If you go through the abstraction process and everything in the code could be parameterized, why not just write the plain code instead ?  If you go the macro route the future code users/readers/maintainers will have to deal with an extra level of abstraction.

 

Suppose the use case indicates the entire step should be macroized to better deal with different prefixes of UCLM and SIGNIFICANCE variables.

The macro changes from a possibly reusable role-based macro to a restricted use process-flow macro.

 

Perhaps something like this

%macro step6_intervals(regions=);
  %* macro name is 'process-flow' based;
  %* significance assignment assigned directly (not via array loop) by
  %* macro generated if/then source code;

  %local i region;

  /* emit source code as boilerplate */

  DATA DATA.REGIONALVALUES6;

    SET DATA.REGIONALVALUES5;

    /* emit 'generated' source */
    /* generated in the sense of resolving macro variables and expressions */

    %do i = 1 %to %sysfunc(countw(&regions));

      %let region = %scan(&regions,&i);

      if &region._HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM then 
        &region._SIGNIFICANCE = 1;
    %end;
  RUN;
%mend;

%step6_intervals(regions=MCR SCR NER)
------------ LOG ------------
577  %step6_intervals(regions=MCR SCR NER)
MPRINT(STEP6_INTERVALS):   DATA DATA.REGIONALVALUES6;
MPRINT(STEP6_INTERVALS):   SET DATA.REGIONALVALUES5;
MPRINT(STEP6_INTERVALS):   if MCR_HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM then MCR_SIGNIFICANCE = 1;
MPRINT(STEP6_INTERVALS):   if SCR_HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM then SCR_SIGNIFICANCE = 1;
MPRINT(STEP6_INTERVALS):   if NER_HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM then NER_SIGNIFICANCE = 1;
MPRINT(STEP6_INTERVALS):   RUN;

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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
  • 2 replies
  • 515 views
  • 2 likes
  • 3 in conversation