I am trying to resolve a macro variable from within a macro call and it will not resolve and I don't know why. Below is my code and the log.
Any assistance will be greatly appreciated.
data _NULL_;
if 0 then set final nobs=n;
call symput('nrows',trim(left(put(n,8.))));
stop;
run;
%put nobs=&nrows;
%global obscount fini_total;
proc sql;
select count(*) into: fini_total
from final
;
quit;
proc freq data= final;
tables Message_Number /
list missing out=frequency;
run;
DATA freq_total;
SET frequency;
SAMPSIZE=(PERCENT*&fini_total.)/100;
_NSIZE_=ROUND(SAMPSIZE,1);
IF _NSIZE_ gt 0;
RUN;
proc sql noprint;
select count(*)
into :obscount
from freq_total;
quit;
%macro recs();
/******* RUN THIS If FINAL has RECORDS ********/
data _null_;
if &nofac < &obscount then call symput ('N',&obscount);
else if &nofac > &fini_total then call symput ('N',&fini_total);
else call symput ('N',&nofac);
run;
proc surveyselect data=final
n=&&N out=ALERT_LIST_Sample;
strata 'Message_Number'n / alloc=prop;
run;
%PUT N=&&N;
%mend recs;
%macro norecs();
/******* RUN THIS If NO RECORDS - TO PRODUCE A 0 RECORD REPORT ********/
data ALERT_LIST_SAMPLE;
set final;
run;
%mend norecs;
data _null_;
if &nrows. = 0 then call execute('%norecs');
else call execute('%recs');
run;
296
297 %macro recs();
298 /******* RUN THIS If FINAL has RECORDS ********/
299 data _null_;
300 if &nofac < &obscount then call symput ('N',&obscount);
301 else if &nofac > &fini_total then call symput ('N',&fini_total);
302 else call symput ('N',&nofac);
303 run;
304
305 proc surveyselect data=final
306 n=&&N out=ALERT_LIST_Sample;
307 strata 'Message_Number'n / alloc=prop;
308 run;
309
310 %PUT N=&&N;
311
312 %mend recs;
313
314 %macro norecs();
315 /******* RUN THIS If NO RECORDS - TO PRODUCE A 0 RECORD REPORT ********/
316
317 data ALERT_LIST_SAMPLE;
318 set final;
319 run;
320
321 %mend norecs;
322
323 data _null_;
324 if &nrows. = 0 then call execute('%norecs');
325 else call execute('%recs');
326 run;
WARNING: Apparent symbolic reference N not resolved.
WARNING: Apparent symbolic reference N not resolved.
11 The SAS System 07:19 Thursday, May 31, 2018
N=&N
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
user cpu time 0.00 seconds
system cpu time 0.00 seconds
memory 250.65k
OS Memory 19116.00k
Timestamp 05/31/2018 08:05:02 AM
Step Count 24 Switch Count 40
Page Faults 0
Page Reclaims 17
Page Swaps 0
Voluntary Context Switches 106
Involuntary Context Switches 2
Block Input Operations 16
Block Output Operations 0
NOTE: CALL EXECUTE generated line.
1 + data _null_; if 9 < 4 then call symput ('N', 4); else if 9 > 26 then call
symput ('N', 26); else call symput ('N', 9); run;
You're actually looking at a quirk of CALL EXECUTE here. It runs macro code immediately, but runs SAS language code (DATA and PROC steps) later. In this case, when CALL EXECUTE generates: %recs the %PUT statement attempts to run immediately. But at that point &N doesn't exist yet. The DATA and PROC steps run later, creating &N but it is too late at that point. The generic fix for this sort of issue:
else call execute('%nrstr(%recs)');
Looking at you code you may not need the double ampersand here, single is fine:
proc surveyselect data=final
n=&&N out=ALERT_LIST_Sample;
strata 'Message_Number'n / alloc=prop;
run;
Its quite simple, macro is resolved before datastep is run. N is created as part of the datastep, so it does not exist at the time the macro is being resolved. To be fair, that is a mess of code and you may have other problems in there. Try to step back an think logically and compartmentalise things, use Base SAS rather than macro.
What does this do?
data _NULL_;
if 0 then set final nobs=n;
call symput('nrows',trim(left(put(n,8.))));
stop;
run;
It creates a whole datastep to get number of observations, then create a macro variable, then later on thats used in another datastep...
Wouldn't:
data _null_; set sashelp.vtable (where=(libname="WORK" and memname="FINAL")); if nobs=0 then call execute('%norecs ();'); else call execute('%recs ();'); run;
Be simpler?
You then have created a global macro variable, to use in a macro, for no reason, as that macro and creation can just be moved into the macro recs().
You're actually looking at a quirk of CALL EXECUTE here. It runs macro code immediately, but runs SAS language code (DATA and PROC steps) later. In this case, when CALL EXECUTE generates: %recs the %PUT statement attempts to run immediately. But at that point &N doesn't exist yet. The DATA and PROC steps run later, creating &N but it is too late at that point. The generic fix for this sort of issue:
else call execute('%nrstr(%recs)');
Hi,
As others have said, from the documentation:
In the Details section:
Because macro references execute immediately and SAS statements do not execute until after a step boundary, you cannot use CALL EXECUTE to invoke a macro that contains references for macro variables that are created by CALL SYMPUT in that macro.
The %PUT N=&&N in macro %recs executes before the null data step with the call execute completes and before the call symput to assign N is executed.
There is a tip in the Details section on how this can be avoided:
The following example uses the %NRSTR macro quoting function to mask the macro statement. This function will delay the execution of macro statements until after a step boundary
call execute('%nrstr(%sales('||month||'))');
Regards,
Amir.
Thank you all, I was able to get my issue resolved and clean up my code.
@Elliott wrote:
Thank you all, I was able to get my issue resolved and clean up my code.
You are working too hard to determine if a data set has NO records. There is no need to know the number of recs. Simply check for EOF before you try to read any records.
This example is contrived. You will need to determine what you DO when there are no records.
26 data _null_;
27 if eof then do;
28 putlog 'NO Records what will I do?';
29 end;
30 stop;
31 set sashelp.class end=eof;
32 where sex eq 'X';
33 run;
NO Records what will I do?
NOTE: There were 0 observations read from the data set SASHELP.CLASS.
WHERE sex='X';
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.
Ready to level-up your skills? Choose your own adventure.