BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Multipla99
Quartz | Level 8

The question below is related to the following answer: Solved: Macro error Apparent symbolic reference - SAS Support Communities

 

I have an example where code similar to below is run and the WARNING: and ERROR: messages similar to the related question are generated. According to the answer to that question "the only way num_obs is not defined is if the the first query returns no results".

 

However, how should mydata look like, not to generate any value into num_obs and at the same time return no error messages from the proc sql statement.

 

My log is very sparse, options nonotes turned on, and therefore I have no information about what the data set looked like at the time of running. It is also very difficult for me to rerun the program to regenerate the error, but nevertheless I need to understand what actually happened.    

 

proc sql noprint;
select count(*) into :num_obs
from (select distinct var
from mydata);
quit;
%let num_obs=&num_obs.;

WARNING: Apparent symbolic reference num_obs not resolved.
ERROR: The text expression &num_obs. contains a recursive reference to the macro variable num_obs. The macro variable will be assigned the null value.

BTW: I'm running SAS 9.4 (TS1M6)

1 ACCEPTED SOLUTION

Accepted Solutions
Multipla99
Quartz | Level 8

To summarize: 

  1. A previous error set SAS in syntax check mode which meant that procs were not executed.
  2. Thus, the macro variable :num_obs, from my first example, was not generated. Since the syntax still was OK no error messages were presented.
  3. Since the syntax check mode didn't prevent %let statement from being executed an error message was generated due to the missing macro variable.  

Thank you everyone for your input!

View solution in original post

25 REPLIES 25
PaigeMiller
Diamond | Level 26

If I am understanding you properly, this is what you want:

 

%let num_obs=;
proc sql noprint;
    select count(*) into :num_obs
    from (select distinct var
    from mydata);
quit;
--
Paige Miller
Quentin
Super User

Note that this statement:

%let num_obs=&num_obs.;

is not allowed.  As the ERROR message says, the macro language sees this as a recursive reference that it can't handle.

 

In your case, I don't think you need a %LET statement at all.  I think select count(*) will always return a value and create the macro variable NUM_OBS, unless there is an error in your code.

BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
PaigeMiller
Diamond | Level 26

There are rare cases where count(*) does not return a value. Such as when the variable is not in the data set, which indeed would be a programming error.

 

proc sql;
    select count(*) into :macrovar from (select distinct gorilla from sashelp.class);
quit;
%put &=macrovar;

 

It is always a problem when the user selects tiny portions of the LOG instead of showing us the ENTIRE log for this PROC. @Multipla99 show us the ENTIRE log for the PROC of interest next time.

 

--
Paige Miller
Multipla99
Quartz | Level 8

Thank you, PageMiller, for trying to find the answer to my question.

 

However, when I run your code I get the following error message:

ERROR: The following columns were not found in the contributing tables: gorilla.

 

I have no corresponding error message in my log.

 

Showing the log is of no use to anyone as the program starts with the following:

options nonotes nomprint nomlogic nosymbolgen nosource nosource2;

 

Thus it's only WARNING and ERROR that gets through to the log.
 

PaigeMiller
Diamond | Level 26

Run my first code, not the gorilla code which was just an example where an error occurs.

 

Showing the log is of no use to anyone as the program starts with the following:

options nonotes nomprint nomlogic nosymbolgen nosource nosource2;

 

Then issue the opposite command.

 

options notes source;

and show us the ENTIRE log for this PROC SQL and macro variable assignment code.

--
Paige Miller
Multipla99
Quartz | Level 8

When I run your first code I get the following error message. 

 

ERROR: File WORK.MYDATA.DATA does not exist.

 

However, this error message is also absent in my log.

 

Unfortnately it's very difficult for me to rerun the code to regenarate a log with more information.

PaigeMiller
Diamond | Level 26

You, @Multipla99, in your original code, referred to data set MYDATA. You need to replace this with an actual data set name.

 

Unfortnately it's very difficult for me to rerun the code to regenarate a log with more information.

 

I don't believe that for a minute. You just ran the code and showed error messages. Just place the options right before your PROC SQL.

--
Paige Miller
Tom
Super User Tom
Super User

@Quentin wrote:

Note that this statement:

%let num_obs=&num_obs.;

is not allowed.  As the ERROR message says, the macro language sees this as a recursive reference that it can't handle.

 

In your case, I don't think you need a %LET statement at all.  I think select count(*) will always return a value and create the macro variable NUM_OBS, unless there is an error in your code.


That is not a recursive reference.

It is a common method to remove leading/trailing spaces from a macro variable that might have been introduced by using the old CALL SYMPUT() function or by the INTO clause of PROC SQL.

 

But it is easy to remove the need to remove those spaces by not creating to begin with:

In PROC SQL you can prevent the leading/trailing spaces by added the TRIMMED keyword.

In DATA step you can prevent the leading/trailing spaces by using the new (15 year old?) CALL SYMPUTX() function instead.

Quentin
Super User

@Tom wrote:

@Quentin wrote:

Note that this statement:

%let num_obs=&num_obs.;

is not allowed.  As the ERROR message says, the macro language sees this as a recursive reference that it can't handle.

 

In your case, I don't think you need a %LET statement at all.  I think select count(*) will always return a value and create the macro variable NUM_OBS, unless there is an error in your code.


That is not a recursive reference.

It is a common method to remove leading/trailing spaces from a macro variable that might have been introduced by using the old CALL SYMPUT() function or by the INTO clause of PROC SQL.

 

In PROC SQL you and prevent the leading/trailing spaces by added the TRIMMED keyword.

In DATA step you can prevent the leading/trailing spaces by using the new (15 year old?) CALL SYMPUTX() function instead.


Thanks for the correction @Tom .

 

You are of course correct, %let foo=&foo; is only seen as an attempt to create a recursive reference if the macro variable FOO does not exist prior to the execution of this statement.  In that case SAS is correctly avoiding the creation of a recursive reference. Indeed I had forgotten that this approach was common before the introduction of TRIMMED.

BASUG is hosting free webinars Next up: Mark Keintz presenting History Carried Forward, Future Carried Back: Mixing Time Series of Differing Frequencies on May 8. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
Tom
Super User Tom
Super User

If you are concerned the define the macro variable.

 

For example if you are using PROC SQL to define the variable then set some default value before executing the statement that you expect to assign a new value.  Then you know the macro variable will exist.  And it will also prevent you from using some stale value of the macro variable that was not replaced for some reason.

proc sql;
%let name=NOT FOUND;
select name into :name trimmed
  from sashelp.class
  where age > 30
;
quit;
%put &=name;
Tom
Super User Tom
Super User

You can check if a macro variable is defined using %SYMEXIST() function and then define it.

%if not %symexist(num_obs) %then %do;
  %global num_obs;
%end;
Multipla99
Quartz | Level 8

The problem is not that I want to check if a macro varible exist but rather how I got the messages:

 

WARNING: Apparent symbolic reference num_obs not resolved.
ERROR: The text expression &num_obs. contains a recursive reference to the macro variable num_obs. The macro variable will be assigned the null value.

  

Without having any error messages from Proc SQL. 

Tom
Super User Tom
Super User

It is easy to do, but not with COUNT().  Just run a query that does not return any observations.  That does not cause any SQL error,  But the INTO never writes to the macro variable since there is nothing to write. 

 

I posted an example earlier.

234  proc sql noprint;
235  %let name=none;
236  select name into :name trimmed from sashelp.class where age>30;
NOTE: No rows were selected.
237  %put &=name;
NAME=none
238  quit;
PaigeMiller
Diamond | Level 26

@Multipla99 wrote:

The problem is not that I want to check if a macro varible exist but rather how I got the messages:

 

WARNING: Apparent symbolic reference num_obs not resolved.
ERROR: The text expression &num_obs. contains a recursive reference to the macro variable num_obs. The macro variable will be assigned the null value.

  

Without having any error messages from Proc SQL. 


OK, you should still show us the ENTIRE log from PROC SQL, even if there are no errors, which is what I requested. 

 

But, if you run my original code, changing MYDATA to the actual data set name, you should get a meaningful result.

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