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(®ION));
%LET REGIONS= %SCAN(®ION,&i);
%put ®IONS;
DATA DATA.REGIONALVALUES6;
SET DATA.REGIONALVALUES5;
IF (®IONS._HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM) THEN ®IONS._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(®ION));
5043 %LET REGIONS= %SCAN(®ION,&i);
5044 %put ®IONS;
5045
5046 DATA DATA.REGIONALVALUES6;
5047 SET DATA.REGIONALVALUES5;
5048
5049 IF (®IONS._HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM) THEN
5049! ®IONS._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
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_®ions, so that when you call the macro, it would create DATA.REGIONALVALUES6_MCR DATA.REGIONALVALUES6_SCR and DATA.REGIONALVALUES6_NER.
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 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(®ions)); %let region = %scan(®ions,&i); if ®ion._HIB_COMPLETE_UCLM < STATE_HIB_COMPLETE_LCLM then ®ion._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;
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!
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.