DATA Step, Macro, Functions and more

Resolving a Macro Variable within a Macro

Accepted Solution Solved
Reply
Frequent Contributor
Posts: 94
Accepted Solution

Resolving a Macro Variable within a Macro

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 Smiley Surprisedbscount

               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;

 

 


Accepted Solutions
Solution
3 weeks ago
Super User
Posts: 6,637

Re: Resolving a Macro Variable within a Macro

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)');

 

 

View solution in original post


All Replies
Valued Guide
Posts: 560

Re: Resolving a Macro Variable within a Macro

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;

Thanks,
Suryakiran
Super User
Super User
Posts: 9,427

Re: Resolving a Macro Variable within a Macro

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().  

Solution
3 weeks ago
Super User
Posts: 6,637

Re: Resolving a Macro Variable within a Macro

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)');

 

 

Super Contributor
Posts: 324

Re: Resolving a Macro Variable within a Macro

Hi,

 

As others have said, from the documentation:

 

http://support.sas.com/documentation/cdl/en/mcrolref/62978/HTML/default/viewer.htm#n1q1527d51eivsn1o...

 

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.

Frequent Contributor
Posts: 94

Re: Resolving a Macro Variable within a Macro

Thank you all, I was able to get my issue resolved and clean up my code.

Respected Advisor
Posts: 3,847

Re: Resolving a Macro Variable within a Macro


@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';
Frequent Contributor
Posts: 94

Re: Resolving a Macro Variable within a Macro

Posted in reply to data_null__
Thanks!
☑ This topic is solved.

Need further help from the community? Please ask a new question.

Discussion stats
  • 7 replies
  • 135 views
  • 1 like
  • 6 in conversation