Help using Base SAS procedures

Nested Macro question

Accepted Solution Solved
Reply
Contributor
Posts: 45
Accepted Solution

Nested Macro question

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)


Accepted Solutions
Solution
‎07-07-2015 01:23 PM
Super User
Posts: 5,080

Re: Nested Macro question

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


All Replies
Super User
Posts: 10,483

Re: Nested Macro question

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.

Solution
‎07-07-2015 01:23 PM
Super User
Posts: 5,080

Re: Nested Macro question

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.

Super User
Super User
Posts: 6,499

Re: Nested Macro question

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;

Super User
Super User
Posts: 6,499

Re: Nested Macro question

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.

Contributor
Posts: 45

Re: Nested Macro question

Thank so much everyone! Smiley Happy

Regular Contributor
Posts: 198

Re: Nested Macro question

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.

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 6 replies
  • 364 views
  • 7 likes
  • 5 in conversation