hello everyone,
%macro p2(datos,clase1,clase2);
proc tabulate data=&datos format=commax10.;
class ANYO;
class &clase1 &clase2/ missing preloadfmt order=data mlf;
tables &clase1*&clase2 all="Total";
%if "&clase1"=A %then .............;
%if "&clase1"=B %then .............;
%if "&clase1"=C %then .............;
%if "&clase1"=D %then .............;
%if "&clase1"=E %then .............;
..............;
%if "&clase1"=X %then .............;
%if "&clase1"=Y %then .............;
%if "&clase1"=Z %then .............;
%if "&clase1"="SEXO" %then
format &clase1 SEXO.;
run;
%mend;
%p1(people,SEXO,EDAD);
I get this message: "WARNING: Variable RUN not found in data set WORK.people" What does it mean?? Why I get it and how I can solve it without %do; ... %end;??
You need a semicolon after format statement, the semicolon you have there ends %if-%then block
%macro p2(datos,clase1,clase2);
proc tabulate data=&datos format=commax10.;
class &clase1 &clase2/ missing preloadfmt order=data mlf;
tables &clase1*&clase2 all="Total";
%if "&clase1"=A %then .............;
%if "&clase1"=B %then .............;
%if "&clase1"=C %then .............;
%if "&clase1"=D %then .............;
%if "&clase1"=E %then .............;
..............;
%if "&clase1"=X %then .............;
%if "&clase1"=Y %then .............;
%if "&clase1"=Z %then .............;
%if "&clase1"="SEXO" %then
format &clase1 SEXO.; /* <- THIS semicolon ends the %if-%then statement NOT format statement */
run;
%mend;
%p1(people,SEXO,EDAD);
Good practice: use %do; -%end; groups
Bart
You need a semicolon after format statement, the semicolon you have there ends %if-%then block
%macro p2(datos,clase1,clase2);
proc tabulate data=&datos format=commax10.;
class &clase1 &clase2/ missing preloadfmt order=data mlf;
tables &clase1*&clase2 all="Total";
%if "&clase1"=A %then .............;
%if "&clase1"=B %then .............;
%if "&clase1"=C %then .............;
%if "&clase1"=D %then .............;
%if "&clase1"=E %then .............;
..............;
%if "&clase1"=X %then .............;
%if "&clase1"=Y %then .............;
%if "&clase1"=Z %then .............;
%if "&clase1"="SEXO" %then
format &clase1 SEXO.; /* <- THIS semicolon ends the %if-%then statement NOT format statement */
run;
%mend;
%p1(people,SEXO,EDAD);
Good practice: use %do; -%end; groups
Bart
Thanks @yabwon , if there's only one sentence why I need to close %if🤔? if I use more than one sentence, can I use double semicolon ??
..................;
.................;
%if "&clase1"="SEXO_1F" %then
format &clase1 SEXO.;;
run;
%mend;
You need a semicolon to end the macro language statement:
%if "&clase1"="SEXO_1F" %then
format &clase1 SEXO.;;
run;
%mend;
Mind the order of colours! Red semicolon and then the blue one,
the same way you would "close" the put statement:
%put some text to print ; /* this semicolon ends the %put statement */
If you have a 4GL code which contains semicolons you basically have to use %do;-%end; block
This will fail:
%macro p1(datos,clase1,clase2);
data _nulL_;
%if "&clase1"="SEXO" %then
format &clase1 dollar12.2; &clase1=17; y=42; ;
run;
%mend;
%p1(people,SEXO,EDAD);
because the semicolon after "dollar12.2
" is interpreted as %if-%then statement end;
Log looks like this:
1 %macro p1(datos,clase1,clase2);
2
3 data _nulL_;
4
5 %if "&clase1"="SEXO" %then
6 format &clase1 dollar12.2; &clase1=17; y=42; ;
7
8 run;
9 %mend;
10
11 %p1(people,SEXO,EDAD);
NOTE: Line generated by the invoked macro "P1".
6 &clase1=17; y=42; ; run;
-
85
76
ERROR 85-322: Expecting a format name.
ERROR 76-322: Syntax error, statement will be ignored.
NOTE: The SAS System stopped processing this step because of errors.
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.01 seconds
But if you add %do;-%end; block everything works fine:
%macro p1(datos,clase1,clase2);
data _nulL_;
%if "&clase1"="SEXO" %then
%do;
format &clase1 dollar12.2; &clase1=17; y=42;
%end;
run;
%mend;
%p1(people,SEXO,EDAD);
Log:
1 %macro p1(datos,clase1,clase2);
2
3 data _nulL_;
4
5 %if "&clase1"="SEXO" %then
6 %do;
7 format &clase1 dollar12.2; &clase1=17; y=42;
8 %end;
9
10 run;
11 %mend;
12
13 %p1(people,SEXO,EDAD);
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
Remember all the "hardness" of macro programming is that your code (the macro language statements) and your data (the 4GL code) are mixed together in one place (a text file with code), so you have to have precise rules to tell SAS which is which.
Bart
%if "&clase1"=A %then
never true. The quotes are part of the comparison.
If all of the variables likely to be used in this macro exist in the data set, i.e. the data set always has the same structure just using different versions of the data, then just have all the format statements as part of the code. The worst that would happen is if the variable in the FORMAT statement doesn't exist is a warning in the log. If the variables are there but not used you don't have to worry about any of these conditional assignments.
If you conditions involve style elements or table structure that is a different story.
BTW, if you are using the macro to make multiple tables you may consider multiple table statements in Proc Tabulate and not have to make multiple calls. Many people don't realize that Proc Tabulate (and Freq) will allow multiple different table statements such as:
proc tabulate data=sashelp.class; class sex age; var height weight; table sex,age; table sex*age, height*(min mean max); table sex, age*weight*(mean stddev) ; run;
Tabulate will require that a variable be used in the same role for all table requests though. So if you want to use a variable as a CLASS variable in one table and VAR variable in a different table then multiple calls to tabulate will be required.
ok. you're right @ballardw, I wanted to say:
%if &clase1=A %then ..........
When you have a single statement that spans multiple lines it will make the program much easier for humans to read if you place the semicolon that ends the statement on its own line. So your %IF statement should look like:
%if "&clase1"="SEXO" %then
format &clase1 SEXO.
;
Now it is more obvious that the FORMAT statement does not have an ending semicolon.
But it is better practice when a macro statement like %IF is controlling the generation of complete statements (not just fragments) to use explicit %DO/%END block.
%if "&clase1"="SEXO" %then %do;
format &clase1 SEXO. ;
%end;
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.
Find more tutorials on the SAS Users YouTube channel.