Hello,
I'm currently trying to update a single-parameter macro, to two parameters.
The reason is that my initial macro creates a data-set, based on a certain summary statistic that I calculate inside the macro.
Now, I want to add a second parameter, that let's me call the macro and create a data-set based on a variety of summary statistics, but I am getting an error.
In my original macro, I have:
%MACRO create_Table1(y);
%DO i = 1 %TO 10;
*Table 1 Calculate 10th percentile;
PROC MEANS DATA = table_&y&i p10 noprint;
BY year;
VAR var_&y&i ;
OUTPUT OUT = stat_&y&i P10(var_&y&i) = var_&y&i ;
RUN;
*Insert more code that works fine;
%END
%MEND create_Table1;
%create_table(y1);
This works fine for me.
Now, I want it so that I can call the macro to calculate either p10 or p50, based on my parameters.
So I tried:
%MACRO create_Table1(y=, statistic=);
%DO i = 1 %TO 10;
*Table 1 Calculate 10th percentile if statistic = p10;
%IF &statistic=p10 %THEN
%DO;
PROC MEANS DATA = table_&y&i p10 noprint;
BY year;
VAR var_&y&i ;
OUTPUT OUT = stat_&y&i P10(var_&y&i) = var_&y&i ;
RUN;
%END;
*Table 2 Calculate 50th percentile if statistic = p50;
%ELSE %IF &statistic=p50 %THEN
%DO;
PROC MEANS DATA = table_&y&i p50 noprint;
BY year;
VAR var_&y&i ;
OUTPUT OUT = stat_&y&i P50(var_&y&i) = var_&y&i ;
RUN;
%END;
*Insert more code that works fine;
%END
%MEND create_Table1;
*Create table with 10th percentile;
%create_table1(y1,p10);
*Create table with 50th percentile;
%create_table1(y1,p50);
But when I try to mend my macro, I get an error:
%ELSE %IF &statistic=p50 %THEN
ERROR: There is no matching %IF statement for the %ELSE.
ERROR: A dummy macro will be compiled.
2739 %DO;
So, I'm wondering, have I messed up the formatting here, or is there potentially another
issue at large?
You cannot insert a statement between the %THEN clause and the %ELSE clause.
To the macro processor your comment is a statement.
Personally I place the comments inside the macro code, not before them. Then they print in the log when the MPRINT option is on.
%IF &statistic=p10 %THEN %DO;
*Table 1 Calculate 10th percentile if statistic = p10;
PROC MEANS DATA = table_&y&i p10 noprint;
BY year;
VAR var_&y&i ;
OUTPUT OUT = stat_&y&i P10(var_&y&i) = var_&y&i ;
RUN;
%END;
%ELSE %IF &statistic=p50 %THEN %DO;
*Table 2 Calculate 50th percentile if statistic = p50;
...
%END;
You could also use either a block comment or a macro comment and it wouldn't count as a statement in between. But then they won't print in the SAS log when MPRINT is on and the users of your macro will have a harder time understanding the log.
Types of comments:
* SAS comment ;
/* Block comment */
%* Macro comment ;
You cannot insert a statement between the %THEN clause and the %ELSE clause.
To the macro processor your comment is a statement.
Personally I place the comments inside the macro code, not before them. Then they print in the log when the MPRINT option is on.
%IF &statistic=p10 %THEN %DO;
*Table 1 Calculate 10th percentile if statistic = p10;
PROC MEANS DATA = table_&y&i p10 noprint;
BY year;
VAR var_&y&i ;
OUTPUT OUT = stat_&y&i P10(var_&y&i) = var_&y&i ;
RUN;
%END;
%ELSE %IF &statistic=p50 %THEN %DO;
*Table 2 Calculate 50th percentile if statistic = p50;
...
%END;
You could also use either a block comment or a macro comment and it wouldn't count as a statement in between. But then they won't print in the SAS log when MPRINT is on and the users of your macro will have a harder time understanding the log.
Types of comments:
* SAS comment ;
/* Block comment */
%* Macro comment ;
Thanks, this solved it.
I would have never figured this out!
You may want to look into the AUTONAME option when creating output data sets.
Please examine (print or view the table) the results of running this code on a data set you should have available:
Proc means data=sashelp.class noprint; class sex; var height weight; output out=work.summary mean= max= min= std= / autoname; run;
The autoname appends the statistic to the variable name (assuming the variable name + _ + statistic is 32 or fewer characters) so you might be able to reduce the calls to proc means/summary in a different fashion by calling either all the statistics or all the variables or both at one time.
If you really are only calling one statistic for one variable you can use <statistic>= ; with nothing else and the name of the output statistic is the variable name:
Proc means data=sashelp.class noprint; class sex; var weight; output out=work.summary skew= ; run;
Your macro as written doesn't need any branching.
Just use the value of the macro variable at the appropriate place in the code.
%MACRO create_Table(y,statistic);
%local i;
%DO i = 1 %TO 10;
* Use PROC MEANS to generate requested statistic ;
PROC MEANS DATA = table_&y&i &statistic noprint;
BY year;
VAR var_&y&i ;
OUTPUT OUT = stat_&y&i &statistic(var_&y&i) = var_&y&i ;
RUN;
*Insert more code that works fine;
%END
%MEND create_Table;
You can even get rid of the %DO loop. Put all 10 of your VAR_&Y.1 to 10 variables into one input dataset and generate the statistic for all of them in one PROC into one output dataset.
%MACRO create_Table(y,statistic);
* Use PROC MEANS to generate requested statistics ;
PROC MEANS DATA = table_&y &statistic noprint;
BY year;
VAR var_&y.1 - var_&y.10 ;
OUTPUT OUT = stat_&y &statistic=;
RUN;
*Insert more code that works fine;
%MEND create_Table;
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.