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

SAS Studio 3.8.

 

The subject line sounds odd, I know. But I couldn't figure out how to better summarize the issue.

 

I have code that returns the number of observations in a dataset via the macro var 'NOBS'. I am trying to wrap this code into a macro so I can efficiently send it different datasets. But the macro only works if I run the inner code of the macro by itself first. Here's what I mean:

 

The dataset sashelp.baseball has 322 obs, so I should see NOBS=322 when I run the following macro:

%macro count_me_obs(my_ds);
  %let dsid = %sysfunc(open(&my_ds.));
  %let nobs = %sysfunc(attrn(&dsid.,nlobs));
  %let dsid = %sysfunc(close(&dsid.));
%mend count_me_obs;

%let getnobs = %count_me_obs(Sashelp.Baseball);
%put &=nobs;
/* Should return NOBS=322 */

Instead I get "WARNING: Apparent symbolic reference NOBS not resolved." as seen below.

 1          OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 68         
 69         %macro count_me_obs(my_ds);
 70           %let dsid = %sysfunc(open(&my_ds.));
 71           %let nobs = %sysfunc(attrn(&dsid.,nlobs));
 72           %let dsid = %sysfunc(close(&dsid.));
 73         %mend count_me_obs;
 74         
 75         %let getnobs = %count_me_obs(Sashelp.Baseball);
 76         %put &=nobs;
 WARNING: Apparent symbolic reference NOBS not resolved.
 nobs
 77

However, if I then run the following code (the guts of the macro):

%let dsid = %sysfunc(open(Sashelp.Baseball));
%let nobs = %sysfunc(attrn(&dsid.,nlobs));
%let dsid = %sysfunc(close(&dsid.));
%put &=nobs;

I correctly get this in my log:

 1          OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 68         
 69         %let dsid = %sysfunc(open(Sashelp.Baseball));
 70         %let nobs = %sysfunc(attrn(&dsid.,nlobs));
 71         %let dsid = %sysfunc(close(&dsid.));
 72         %put &=nobs;
 NOBS=322
 73         
 74         
 75         OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;

NOW if I run the macro again, I correctly get the NOBS=322 in my log. Before you think that it's just putting in the previous value of NOBS, I can send other datasets to the macro and those get counted correctly now too, like so:

%macro count_me_obs(my_ds);
  %let dsid = %sysfunc(open(&my_ds.));
  %let nobs = %sysfunc(attrn(&dsid.,nlobs));
  %let dsid = %sysfunc(close(&dsid.));
%mend count_me_obs;

%let getnobs = %count_me_obs(Sashelp.Baseball);
%put &=nobs;
/* NOBS=322 */
%let getnobs = %count_me_obs(Sashelp.Class); %put &=nobs; /* NOBS=19 */
%let getnobs = %count_me_obs(Sashelp.Gas); %put &=nobs; /* NOBS=171 */
%let getnobs = %count_me_obs(Sashelp.Springs); %put &=nobs;
/* NOBS=1587 */

which gives me this log:

1          OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 68         
 69         %macro count_me_obs(my_ds);
 70           %let dsid = %sysfunc(open(&my_ds.));
 71           %let nobs = %sysfunc(attrn(&dsid.,nlobs));
 72           %let dsid = %sysfunc(close(&dsid.));
 73         %mend count_me_obs;
 74         
 75         %let getnobs = %count_me_obs(Sashelp.Baseball);
 76         %put &=nobs;
 NOBS=322
 77         
 78         %let getnobs = %count_me_obs(Sashelp.Class);
 79         %put &=nobs;
 NOBS=19
 80         
 81         %let getnobs = %count_me_obs(Sashelp.Gas);
 82         %put &=nobs;
 NOBS=171
 83         
 84         %let getnobs = %count_me_obs(Sashelp.Springs);
 85         %put &=nobs;
 NOBS=1587
 86         

So to recap: The macro doesn't work until I run the inner part of code by itself first. Then the  whole macro works all day long. It's almost like I have to slap NOBS around first to wake it up, then it performs properly.

 

Of course, I need the code to work the first time it runs. Am I missing a step or something else? Thanks!

1 ACCEPTED SOLUTION

Accepted Solutions
SASKiwi
PROC Star

That's because the macro variable NOBS is first defined within your macro count_me_obs so is only local to that macro. Add a %GLOBAL statement to ensure NOBS is available outside your macro:

%macro count_me_obs(my_ds);
  %global nobs;
  %let dsid = %sysfunc(open(&my_ds.));
  %let nobs = %sysfunc(attrn(&dsid.,nlobs));
  %let dsid = %sysfunc(close(&dsid.));
%mend count_me_obs;

View solution in original post

4 REPLIES 4
SASKiwi
PROC Star

That's because the macro variable NOBS is first defined within your macro count_me_obs so is only local to that macro. Add a %GLOBAL statement to ensure NOBS is available outside your macro:

%macro count_me_obs(my_ds);
  %global nobs;
  %let dsid = %sysfunc(open(&my_ds.));
  %let nobs = %sysfunc(attrn(&dsid.,nlobs));
  %let dsid = %sysfunc(close(&dsid.));
%mend count_me_obs;
iggles
Fluorite | Level 6

Thank you! That was indeed my issue. Solution worked like a charm and I'm a little more knowledgeable now for it 🙂

Kurt_Bremser
Super User

Keeping track of scope is very important when doing macro coding. Macro variables that should "result" from the macro must be defined as global (or you won't see them outside the macro), while variables used only for the functioning of the macro itself must be defined as local to avoid unwanted side effects.

 

Macro definitions, OTOH, exist side-by-side in the global scope (that's why defining a macro inside another makes no sense and only reduces code readability).

PaigeMiller
Diamond | Level 26

Another solution is to have the macro create text as its output, using the variable &NOBS, so that the assignment statement %LET GETNOBS is assigned a value:

 

%macro count_me_obs(my_ds);
  %let dsid = %sysfunc(open(&my_ds.));
  %let nobs = %sysfunc(attrn(&dsid.,nlobs));
  %let dsid = %sysfunc(close(&dsid.));
  &nobs
%mend count_me_obs;

%let getnobs = %count_me_obs(sashelp.baseball);
%put &=getnobs;
--
Paige Miller

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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
  • 4 replies
  • 404 views
  • 6 likes
  • 4 in conversation