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;
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.
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.
Great, thanks Kurt!
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;
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;
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
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)
PS options mlogic mprint is just there to show you what happens. It's not a solution, as you have not stated what issue you need to solve with the code.
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) || ')') );
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;
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) || '))' );
Great, this is exactly what I needed. Thanks for your help.
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.
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.