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

Good afternoon,

I am having an issue with a nested macro. My code is listed below. The first time (1998) the %year macro is running, there is no problem. ODS is creating the datastats_1998 data set with whatever I need. The second time it runs (1999) I get the following message in the log, which makes me think that I have forgotten something in ODS. I tried to use "ods output close" at the end of the macro, but it did not fix the problem. Does anybody know what am I doing wrong?

WARNING: Output 'ChiSq' was not created.  Make sure that the output object name, label, or path

         is spelled correctly.  Also, verify that the appropriate procedure options are used to

         produce the requested output object.  For example, verify that the NOPRINT option is

         not used.

%macro center(center);

data frequency;

set irnd;

where center=&center;

run;

%Macro year(year);

data frequency;

length check $20;

set frequency;

if year=&year then check="&year";

else if year=&year+1 then check="Next Year";

else delete;

run;

ods output ChiSq=datastats_&year;

proc freq data=frequency;

tables OCGRDCLN*check / chisq;

run;

proc print data=datastats_&year;

run;

%mend year;

%year(1998)

%year(1999)

%mend center;

%center(3)

1 ACCEPTED SOLUTION

Accepted Solutions
Astounding
PROC Star

I agree with ballardw's suggestion ... bad form to define one macro inside the definition of another macro.  But as to your problem, it has a different source.  You are reusing the FREQUENCY data set several times.  After running %year(1998), there are only two years left in the FREQUENCY data set (1998 and 1999).  When you next run %year(1999), you are deleting the 1998 observations, and are left with only 1999 observations.  You don't end up with any year=2000 observations, because those were deleted when running %year(1998).  With only one year of data, it's not possible to compute chi squares.

View solution in original post

6 REPLIES 6
ballardw
Super User

It is generally considered a bad idea to define a macro within another macro as debugging gets much more complex.

It would be better to define the Year macro separately and pass any additional information needed as parameters, or possibly one macro passing the Center and Year parameters.

You might try putting the ods output ChiSq=datastats_&year; within the proc freq code.

proc freq data=frequency;

tables OCGRDCLN*check / chisq;

ods output ChiSq=datastats_&year;

run;

So the output goes along with the actual version of the procedure run.

Astounding
PROC Star

I agree with ballardw's suggestion ... bad form to define one macro inside the definition of another macro.  But as to your problem, it has a different source.  You are reusing the FREQUENCY data set several times.  After running %year(1998), there are only two years left in the FREQUENCY data set (1998 and 1999).  When you next run %year(1999), you are deleting the 1998 observations, and are left with only 1999 observations.  You don't end up with any year=2000 observations, because those were deleted when running %year(1998).  With only one year of data, it's not possible to compute chi squares.

Tom
Super User Tom
Super User

You could make the YEAR() macro just run with a WHERE clause instead of making a new dataset,

%macro year(year);

ods output ChiSq=datastats_&year;

proc freq data=frequency;

  where year in (&year,%eval(&year+1));

  tables OCGRDCLN*&year / chisq;

run;

proc print data=datastats_&year;

run;

%mend year;

Tom
Super User Tom
Super User

It is the execution of the macros that is nested, not the definition. So move the %macro year... %mend year lines to the top of the program.

Note that your %YEAR() macro is overwriting its input so you cannot call it twice within the other macro without it failing.

Turn the MPRINT option to see what code the macros are really generating.

Greek
Obsidian | Level 7

Thank so much everyone! Smiley Happy

Ron_MacroMaven
Lapis Lazuli | Level 10

several respondents said "it is bad form to define one macro completely within another"

and I agree.

While this may be a common practice in other languages, for scoping reasons etc.,

in the SAS macro language

every time the outer macro is called the inner macro is recompiled, again.

For trivial demonstration macros, we can probably not see the difference in time used.

However, for large macros written by programmers with a 'works-there-let's-do-it-here' attitude

this can be a show-stopper when it comes to optimizing

because the macro processing does not have timing notes like SAS steps do.

I recommend keeping macros small, in separate files,

so both unit and integration tests can be done separately.

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!

What is Bayesian Analysis?

Learn the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.

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
  • 6 replies
  • 1585 views
  • 7 likes
  • 5 in conversation