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

Hello all,

 

I am trying to amend the code that is attached so that I would not have to run it twice to get the desired outcome. When I run it once I get this warning:

WARNING: Apparent symbolic reference A not resolved.

WARNING: Apparent symbolic reference B not resolved.

WARNING: Apparent symbolic reference MONTH_END_DT not resolved.

WARNING: Apparent symbolic reference YM not resolved.

&A &B &month_end_dt &YM

WARNING: Apparent symbolic reference A not resolved.

WARNING: Apparent symbolic reference B not resolved.

WARNING: Apparent symbolic reference MONTH_END_DT not resolved.

WARNING: Apparent symbolic reference YM not resolved.

 

However, after rerunning the code it works fine - any idea how to restructure the code to provide the desired outcome within the first run? Thanks

%macro d(country,cycle);

data _null_;
A = put(intnx('month',mdy(substr(&cycle,1,length(&cycle)-2),1,substr(&cycle,length(&cycle)-1,2)),-1,'end'),date9.)||':23:59:59.000';
CALL SYMPUT('A',A);
B = INPUT(A,DATETIME22.3);
CALL SYMPUT('B',B);
month_end_dt = INTNX('DTMONTH',B,-1,'E');
call symput ('month_end_dt',put(month_end_dt,datetime22.3));
year_month = put(year(datepart(month_end_dt)),4.)||"_"||put(month(datepart(month_end_dt)),Z2.);
call symput ('ym',year_month);
run;

%PUT &A &B &month_end_dt &YM;

%mend d;

data _null_;
   array x[2] $2 ('UK' 'DE');
   	do j=1 to dim(x);
		do i = 1 to 1;
			country = x[j];
			cycle = compress(strip(trim(cat(i,'17'))));
			call execute ('%d('!!trim(country)!!','!!trim(cycle)!!')');
		end;
  	end;
run;
1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

When you call execute a macro, the macro call itself is put into the SAS processing queue, the macro processor kicks in and executes the macro, but all code created by the macro will only be executed once the current data step has finished.

When you activate

options mlgoc mprint;

before the data step that call executes the macro, you'll see that all macro logic runs before the data step ends, and that only then will the data steps created by the macro calls start.

Since these data steps now run outside(!) a macro, they put their macro variables in the global table, so they are available after that.

View solution in original post

12 REPLIES 12
Kurt_Bremser
Super User

When you call execute a macro, the macro call itself is put into the SAS processing queue, the macro processor kicks in and executes the macro, but all code created by the macro will only be executed once the current data step has finished.

When you activate

options mlgoc mprint;

before the data step that call executes the macro, you'll see that all macro logic runs before the data step ends, and that only then will the data steps created by the macro calls start.

Since these data steps now run outside(!) a macro, they put their macro variables in the global table, so they are available after that.

Uknown_user
Quartz | Level 8

Kurt I amended the code as you mentioned (attached) but it still gives the warning message?

%macro d(country,cycle);

data _null_;
A = put(intnx('month',mdy(substr(&cycle,1,length(&cycle)-2),1,substr(&cycle,length(&cycle)-1,2)),-1,'end'),date9.)||':23:59:59.000';
CALL SYMPUT('A',A);
B = INPUT(A,DATETIME22.3);
CALL SYMPUT('B',B);
month_end_dt = INTNX('DTMONTH',B,-1,'E');
call symput ('month_end_dt',put(month_end_dt,datetime22.3));
year_month = put(year(datepart(month_end_dt)),4.)||"_"||put(month(datepart(month_end_dt)),Z2.);
call symput ('ym',year_month);
run;

%PUT &A &B &month_end_dt &YM;

%mend d;

options mlogic mprint;

data _null_;
   array x[2] $2 ('UK' 'DE');
   	do j=1 to dim(x);
		do i = 1 to 1;
			country = x[j];
			cycle = compress(strip(trim(cat(i,'17'))));
			call execute ('%d('!!trim(country)!!','!!trim(cycle)!!')');
		end;
  	end;
run;
Kurt_Bremser
Super User

Eliminate the macro that doesn't do anything (besides putting values to the log):

data _null_;
array x[2] $2 ('UK' 'DE');
do j=1 to dim(x);
  do i = 1 to 1;
    country = x[j];
    cycle = compress(strip(trim(cat(i,'17'))));
    A = put(intnx('month',mdy(substr(cycle,1,length(cycle)-2),1,substr(cycle,length(cycle)-1,2)),-1,'end'),date9.)||':23:59:59.000';
    B = INPUT(A,DATETIME22.3);
    month_end_dt = INTNX('DTMONTH',B,-1,'E');
    year_month = put(year(datepart(month_end_dt)),4.)||"_"||put(month(datepart(month_end_dt)),Z2.);
    put a= b= month_end_dt= year_month=;
  end;
end;
run;
Uknown_user
Quartz | Level 8

The problem is that within the macro there are many sql procedures and datasteps that I did not mention. I just want to loop through the combinations of countries and cycles while there are other macro variables derived from cycle. Thanks

Kurt_Bremser
Super User

Then I'd take all macro logic out of the macro, so it becomes purely a wrapper for the repeating code, and calculate all macro values in the data _null_ step. Use all parameters calculated in the data step as macro parameters.

Make your code as simple as possible, debugging what you had initially is a major PITA (as you have already noticed, or you wouldn't be here)

Astounding
PROC Star

Except for the messages, the results are probably accurate.  CALL EXECUTE runs macro statements such as %PUT right away, before running the DATA step that assigns values to the macro variables.  The solution is to delay running the macro statements by applying %NRSTR:

 

call execute ('%d(' || trim(country) || ',' || trim(cycle) || ')' );

 

becomes 

 

call execute (%nrstr('%d(' || trim(country) || ',' || trim(cycle) || ')') );

Uknown_user
Quartz | Level 8

Hi, I tried what you suggested and received same warning message:

WARNING: Apparent symbolic reference A not resolved.

WARNING: Apparent symbolic reference B not resolved.

WARNING: Apparent symbolic reference MONTH_END_DT not resolved.

WARNING: Apparent symbolic reference YM not resolved.

&A &B &month_end_dt &YM

WARNING: Apparent symbolic reference A not resolved.

WARNING: Apparent symbolic reference B not resolved.

WARNING: Apparent symbolic reference MONTH_END_DT not resolved.


%macro d(country,cycle); data _null_; A = put(intnx('month',mdy(substr(&cycle,1,length(&cycle)-2),1,substr(&cycle,length(&cycle)-1,2)),-1,'end'),date9.)||':23:59:59.000'; CALL SYMPUT('A',A); B = INPUT(A,DATETIME22.3); CALL SYMPUT('B',B); month_end_dt = INTNX('DTMONTH',B,-1,'E'); call symput ('month_end_dt',put(month_end_dt,datetime22.3)); year_month = put(year(datepart(month_end_dt)),4.)||"_"||put(month(datepart(month_end_dt)),Z2.); call symput ('ym',year_month); run; %PUT &A &B &month_end_dt &YM; %mend d; /*options mlogic mprint;*/ data _null_; array x[2] $2 ('UK' 'DE'); do j=1 to dim(x); do i = 1 to 1; country = x[j]; cycle = compress(strip(trim(cat(i,'17')))); call execute (%nrstr('%d(' || trim(country) || ',' || trim(cycle) || ')') ); end; end; run;
Astounding
PROC Star

It's possible the quotes are in the wrong place:

 

call execute (%nrstr('%d(' || trim(country) || ',' || trim(cycle) || ')') );

 

Try it this way:

call execute ('%nrstr(%d(' || trim(country) || ',' || trim(cycle) || '))' );

Uknown_user
Quartz | Level 8

Great, this is exactly what I needed. Thanks for your help.

RW9
Diamond | Level 26 RW9
Diamond | Level 26

So what is it your actually trying to do as this looks like a bit of a pickle.  You say you want to do code for some by groups (country, cycle) - so my first question is going to be, why do you not put country and cycle into the data, and then do by group processing on it.  This would simplify all your coding.

The second thing is that you seem to be creating macro variables for dates, times and such like, probably to use later in the macro.  This again is not a good way to work with "data" as all of that is going to be text (and a more complicated syntax to work with).

From what I can tell from the code you have posted, this is doing nothing more than looping over two countries and one period and outputting a couple of new data elements all of which can be done in a simple datastep:

data _null_;
  do country="UK","DE";
    do cycle=1 to 1;
      a=...;
      b=...;
      ...
      put _all_;
    end;
  end;
run;

Note I didn't bother copying all the calculation code over.  It just seems to me like your complicating an otherwise simple thing.

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
  • 12 replies
  • 1883 views
  • 1 like
  • 4 in conversation