BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Michelle_
Fluorite | Level 6

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;

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

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.

View solution in original post

7 REPLIES 7
Tom
Super User Tom
Super User

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.

Michelle_
Fluorite | Level 6

No error pop up. 
It only able to run one times.  I have write %repeat(3). But, it only able to run &i.= 1

Michelle_
Fluorite | Level 6

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. 

Kurt_Bremser
Super User

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.

Quentin
Super User

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.

 

BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
yabwon
Onyx | Level 15

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

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



sas-innovate-2024.png

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.

 

Register now!

SAS Enterprise Guide vs. SAS Studio

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.

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
  • 625 views
  • 6 likes
  • 5 in conversation