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-white.png

Missed SAS Innovate in Orlando?

Catch the best of SAS Innovate 2025 — anytime, anywhere. Stream powerful keynotes, real-world demos, and game-changing insights from the world’s leading data and AI minds.

 

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 4 replies
  • 1004 views
  • 6 likes
  • 4 in conversation