Hi all, seeking help on how to write a macro to call another macro for different period.
I have different setting to run each month. Im wondering can I write a macro to auto repeat run the same macro.
%macro repeat(n);
%do i = 1 %to &n.;
%if &i. = 1 %then
%do;
%let month = 4;
%let lag = 2;
%end;
%if &i. = 2 %then
%do;
%let month = 7;
%let lag = 2;
%end;
%if &i. = 3 %then
%do;
%let month = 4;
%let lag = 1;
%end;
%month_setting;
%setting;
%end;
%mend;
%repeat(3);
%macro month_setting;
%global begin end;
%if %sysevalf(&lag = 2) %then
%do;
%let begin = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)),-&month.),date9.)"d;
%let end = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)), +&lag.),date9.)"d;
%end;
%else %if %sysevalf(&lag = 1) %then
%do;
%let begin = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)),-&month.+1),date9.)"d;
%let end = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)), +&lag.+1),date9.)"d;
%end;
%let end_YM = %sysfunc(inputn(%sysfunc(substr(%sysfunc(putn(&end., yymmddn8.)),1, 6)), 6.));
%let beg_YM = %sysfunc(inputn(%sysfunc(substr(%sysfunc(putn(&begin., yymmddn8.)),1, 6)), 6.));
%mend;
/*macro sample*/
%macro setting;
Data working.M&Month._Setting;
month = &month.;
lag = &lag.;
begin = put(&begin.,yymmddn8.);
end = put(&end.,yymmddn8.);
run;
%mend;
Sloppy macro programming. Always (as in ALWAYS) define variables used in the macro as local (%LOCAL statement).
Your macro datecreate uses i for the loop, which is also used in repeat; after returning from datecreate, &i will have a large enough value to terminate the loop in repeat.
Did you try the code? Did it work? If not what was wrong?
You can call another macro inside a macro.
But you have to have defined it before you try to CALL it.
So make sure to move the call to %REPEAT() to after the definition of all three macros.
No error pop up.
It only able to run one times. I have write %repeat(3). But, it only able to run &i.= 1
Run your macro with
options mprint mlogic symbolgen;
set and post the log.
Apologies. Can ignore the previous coding i asked. The issue seems like appear after the %datecreate macro.
If only run until %setting then it works. However, when run one more macro (i.e. %datecreate) then it won't auto generate the second and third run.
So, i have create delete specific global macro.
%macro repeat(n);
%do i = 1 %to &n.;
%if &i. = 1 %then
%do;
%let month = 4;
%let lag = 2;
%end;
%if &i. = 2 %then
%do;
%let month = 7;
%let lag = 2;
%end;
%if &i. = 3 %then
%do;
%let month = 4;
%let lag = 1;
%end;
%month_setting;
%setting;
%datecreate;
%deleteALL;
%end;
%mend;
%repeat(3);
%macro month_setting;
%global begin end;
%if %sysevalf(&lag = 2) %then
%do;
%let begin = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)),-&month.),date9.)"d;
%let end = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)), +&lag.),date9.)"d;
%end;
%else %if %sysevalf(&lag = 1) %then
%do;
%let begin = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)),-&month.+1),date9.)"d;
%let end = "%sysfunc(intnx(month,%sysfunc(inputN(&period.01,yymmdd10.)), +&lag.+1),date9.)"d;
%end;
%let end_YM = %sysfunc(inputn(%sysfunc(substr(%sysfunc(putn(&end., yymmddn8.)),1, 6)), 6.));
%let beg_YM = %sysfunc(inputn(%sysfunc(substr(%sysfunc(putn(&begin., yymmddn8.)),1, 6)), 6.));
%mend;
/*macro sample*/
%macro setting;
Data working.M&Month._Setting;
month = &month.;
lag = &lag.;
begin = put(&begin.,yymmddn8.);
end = put(&end.,yymmddn8.);
run;
%mend;
%macro datecreate;
%global dif;
%let dif = %sysfunc(intck(MONTH,&begin,&end));
%do i= 1 %to &dif;
%global date_&i;
%let date_&i=%sysfunc(intnx(month,&begin,&i,B),yymmn6.);
%put &&date_&i;
%end;
%mend;
%macro deleteALL;
options nonotes;
%local vars;
proc sql noprint;
select name into: vars separated by ' '
from dictionary.macros
where scope = 'GLOBAL' and (name contains 'DATE_' or name in ('MONTH', 'LAG', 'BEGIN','END', 'BEG_YM', 'END_YM', 'DIF'));
quit;
%symdel &vars;
options notes;
%put NOTE: Macro variables deleted.;
%mend;
But, the above coding not working also. It didn't pop any errors. However, it will not generate the results for Month 7 + Lag 2 and Month 4 + lag 1.
Sloppy macro programming. Always (as in ALWAYS) define variables used in the macro as local (%LOCAL statement).
Your macro datecreate uses i for the loop, which is also used in repeat; after returning from datecreate, &i will have a large enough value to terminate the loop in repeat.
Kurt has identified the problem, I want to share an example. Suppose you have macros OUTER and INNER where OUTER invokes INNER. You want to have OUTER loop 2 times, and INNER loop 3 times per iteration of OUTER.
If you code it like:
%macro outer(n=) ;
%do i=1 %to &n ;
%put %nrstr(%%)&sysmacroname ;
%put _user_ ;
%put ;
%inner(n=3) ;
%end ;
%mend outer ;
%macro inner(n=) ;
%do i=1 %to &n ;
%put %nrstr(%%)&sysmacroname ;
%put _user_ ;
%put ;
%end ;
%mend inner ;
%outer(n=2)
Your log will show that OUTER is loops once, not twice as intended. This is the problem you're having:
22 %outer(n=2) %OUTER OUTER I 1 OUTER N 2 %INNER INNER N 3 OUTER I 1 OUTER N 2 %INNER INNER N 3 OUTER I 2 OUTER N 2 %INNER INNER N 3 OUTER I 3 OUTER N 2
When OUTER executes, it creates the macro variables i and N.
When INNER executes, it creates a new macro variable N which is a different macro variable than the variable N which exists in outer. It does this because N is defined as macro parameter to INNER.
But when the %DO loop in INNER executes, it does NOT create a new macro variable i for INNER. Instead it uses the macro variable i that already exists in OUTER. So this is a naming collision. INNER has changed the values of a macro variable that belongs to OUTER. And because INNER loops three times, you end up with the macro variable i having the value of 3. Then the %DO loop in OUTER does not loop a second time, because i is already 3.
The way to avoid this problem is to declare the macro variable i to be local in INNER. That way when INNER executes, the %LOCAL statement will create a new local macro variable i for INNER that is separate from the macro variable i in OUTER.
%macro outer(n=) ;
%local i ;
%do i=1 %to &n ;
%put %nrstr(%%)&sysmacroname ;
%put _user_ ;
%put ;
%inner(n=3) ;
%end ;
%mend outer ;
%macro inner(n=) ;
%local i;
%do i=1 %to &n ;
%put %nrstr(%%)&sysmacroname ;
%put _user_ ;
%put ;
%end ;
%mend inner ;
%outer(n=2)
Log:
22 %outer(n=2) %OUTER OUTER I 1 OUTER N 2 %INNER INNER I 1 INNER N 3 OUTER I 1 OUTER N 2 %INNER INNER I 2 INNER N 3 OUTER I 1 OUTER N 2 %INNER INNER I 3 INNER N 3 OUTER I 1 OUTER N 2 %OUTER OUTER I 2 OUTER N 2 %INNER INNER I 1 INNER N 3 OUTER I 2 OUTER N 2 %INNER INNER I 2 INNER N 3 OUTER I 2 OUTER N 2 %INNER INNER I 3 INNER N 3 OUTER I 2 OUTER N 2
With that, outer loops two times, so you get the expected 2*3=6 executions of INNER. And you can see in the log that the macro variables i and N in INNER are independent of the macro variables i and N in OUTER.
you can do it much simpler and much more readable using data step:
libname working (work);
%macro setting(period, i);
data working.P&period._Setting;
period = input(cats(symget('period'),'01'),yymmdd8.);
i = symgetn("i");
select(i);
when(1)
do;
month = 4;
lag = 2;
end;
when(2)
do;
month = 7;
lag = 2;
end;
when(3)
do;
month = 4;
lag = 2;
end;
otherwise put "ERROR: I should be in 1, 2, 3.";
end;
select(lag);
when(2)
do;
b = intnx("month", period,-month);
e = intnx("month", period, +lag);
end;
when(1)
do;
b = intnx("month", period,-month+1);
e = intnx("month", period, +lag+1);
end;
otherwise put "ERROR: LAG shoild be in 1, 2.";
end;
begin = put(b,yymmddn8.);
end = put(e,yymmddn8.);
/* you didnot used those 2 in the code at all */
beg_YM = put(b,yymmn6.);
end_YM = put(e,yymmn6.);
keep month lag begin end beg_YM end_YM ;
run;
%mend;
%setting(202308, 1)
proc print;
run;
%setting(202308, 2)
proc print;
run;
%setting(202308, 3)
proc print;
run;
Bart
Don't miss out on SAS Innovate - Register now for the FREE Livestream!
Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.
What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.
Find more tutorials on the SAS Users YouTube channel.