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

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;

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Astounding
PROC Star

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

7 REPLIES 7
SuryaKiran
Meteorite | Level 14

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
RW9
Diamond | Level 26 RW9
Diamond | Level 26

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

Astounding
PROC Star

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

 

 

Amir
PROC Star

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.

Elliott
Obsidian | Level 7

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

data_null__
Jade | Level 19

@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';
Elliott
Obsidian | Level 7
Thanks!

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
  • 7 replies
  • 1610 views
  • 1 like
  • 6 in conversation