Hello,
In SASHELP.CARS, I would like to make a PROC TABULATE by Origin. So, the first way is to make 3 PROC TABULATE like the following and replace "Asia" by USA and then Europe :
PROC TABULATE DATA = data out=tabulate; where Origin="Asia"; CLASS Make DriveTrain ; TABLE (Make), (DriveTrain) / nocellmerge ; run;
But, instead, I would like to automatize this in a macro loop. Could you please help me why the following code won’t work ? It’s the « where Origin=reg; » part that seems to be the problem. Thank you !
data data; set sashelp.cars;run;
data classes;
input id_reg reg_name $ ;
cards;
1 Asia
2 Europe
3 USA
run;
%macro comp;
%local i reg;
%do i=1 %to 3;
proc sql ;
select reg_name
into
:reg_name
from classes
where id_reg = &i.;
quit;
%let reg=reg_name;
PROC TABULATE DATA = data out=tabulate_&i;
where Origin=reg;
CLASS Make DriveTrain ;
TABLE (Make), (DriveTrain) / nocellmerge ;
run;
%end;
%mend comp;
%comp
Thanks to all the bits you gave, I think I have found the solution, without using the BY statemen. So here is the code that worked for me. I thank you all very much for your help!
data data; set sashelp.cars;run;
data classes;
input id_reg reg_name $ ;
cards;
1 Asia
2 Europe
3 USA
run;
%macro comp;
%local i ;
%do i=1 %to 3;
proc sql ;
select reg_name
into
:reg_name
from classes
where id_reg = &i.;
quit;
PROC TABULATE DATA = data(where=(Origin="®_name")) out=tabulate_&i;
CLASS Make DriveTrain ;
TABLE (Make), (DriveTrain) / nocellmerge ;
run;
%end;
%mend comp;
%comp
No need for a macro. Simply create a "3-dimensional" table like this
PROC TABULATE DATA = sashelp.cars out=tabulate;
CLASS Origin Make DriveTrain;
TABLE Origin, Make, DriveTrain / nocellmerge;
run;
Yes, I understand but I made a simple example. In the real database I work with, I need to make a macro 🙂 this is why I insist on making a macro.
Working with a database doesn't change the validity of the suggestion from @PeterClemmensen
Or if it does make a difference, please explain why.
Hi,
first, use an ampersand &:
PROC TABULATE DATA = data out=tabulate_&i;
where Origin=® /* <-------- an & */
CLASS Make DriveTrain ;
TABLE (Make), (DriveTrain) / nocellmerge ;
run;
second: try:
select quote(reg_name)
into...
since, I believe, you want to have:
where Orgin = "Asia"
rather than:
where Orgin = Asia
after the ®. resolution
third, this part:
%let reg=reg_name;
is redundant, reg_name is already a macrovariable so you can use it inside the proc tabulate (btw. you don't have the "&" here again)
should be: %let reg = ®_name; if you want it to work.
All the best
Bart
I guess I'm going to disagree with @yabwon
This code is easily handled with a BY statement, and no macro or macro variable is needed.
PROC TABULATE DATA = data out=tabulate;
by Origin;
CLASS Make DriveTrain ;
TABLE (Make), (DriveTrain) / nocellmerge ;
run;
@PaigeMiller no need for disagree. I didn't tell I like OPs code. I just pointed out places where the root cause of the "where issue" might be. 😉
All the best
Bart
Sorry, but I don't understand except putting "&". So, here is my code, with your suggestions. But it still does not work:
%macro comp; %local i reg; %do i=1 %to 3; proc sql ; select reg_name into :reg_name from classes where id_reg = &i.; quit; %let reg=input(reg_name,$10); PROC TABULATE DATA = data out=tabulate_&i; where Origin in (®); CLASS Make DriveTrain ; TABLE (Make), (DriveTrain) / nocellmerge ; run; %end; %mend comp; %comp
%macro comp; %local i reg; %do i=1 %to 3; proc sql ; select QUOTE(reg_name) into :reg_name from classes where id_reg = &i.; quit; PROC TABULATE DATA = data out=tabulate_&i; where Origin in (®_name.); CLASS Make DriveTrain ; TABLE (Make), (DriveTrain) / nocellmerge ; run; %end; %mend comp; %comp
Reply made to same question as cross posted to stackoverflow...
Use a `BY` statement to independently process like grouped subsets of a data set.
Use a `WHERE` statement to select the subset(s) to process.
Example:
ods html file='output.html' style=plateau; proc sort data=sashelp.cars out=cars_sorted; by origin; run; title; footnote; options nocenter nodate nonumber; PROC TABULATE DATA=cars_sorted; by origin; where Origin in ("Asia", "Europe", "USA"); where also make >= 'P'; * further subset for reduced size of output screen shot; CLASS Make DriveTrain ; TABLE (Make), (DriveTrain) / nocellmerge ; run; ods html close;
Alternatively, use a `TABLE` statement of form `<page dimension>,<row dimension>,<column dimension>` in lieu of `BY` group processing. Such a form does not need presorted data because the <page dimension> is constructed from `CLASS` variables.
Example:
PROC TABULATE DATA=sashelp.cars; /* original data, not sorted */ where Origin in ("Asia", "Europe", "USA"); where also make >= 'P'; * further subset for reduced size of output screen shot; CLASS Origin Make DriveTrain ; /* Origin added to CLASS */ TABLE Origin, (Make), (DriveTrain) / nocellmerge ; /* Origin is page dimension */ run;
Output BY statement
Output PAGE dimensioned table
Thanks to all the bits you gave, I think I have found the solution, without using the BY statemen. So here is the code that worked for me. I thank you all very much for your help!
data data; set sashelp.cars;run;
data classes;
input id_reg reg_name $ ;
cards;
1 Asia
2 Europe
3 USA
run;
%macro comp;
%local i ;
%do i=1 %to 3;
proc sql ;
select reg_name
into
:reg_name
from classes
where id_reg = &i.;
quit;
PROC TABULATE DATA = data(where=(Origin="®_name")) out=tabulate_&i;
CLASS Make DriveTrain ;
TABLE (Make), (DriveTrain) / nocellmerge ;
run;
%end;
%mend comp;
%comp
@commitsudoku wrote:
Thanks to all the bits you gave, I think I have found the solution, without using the BY statemen. So here is the code that worked for me. I thank you all very much for your help!
data data; set sashelp.cars;run; data classes; input id_reg reg_name $ ; cards; 1 Asia 2 Europe 3 USA run; %macro comp; %local i ; %do i=1 %to 3; proc sql ; select reg_name into :reg_name from classes where id_reg = &i.; quit; PROC TABULATE DATA = data(where=(Origin="®_name")) out=tabulate_&i; CLASS Make DriveTrain ; TABLE (Make), (DriveTrain) / nocellmerge ; run; %end; %mend comp; %comp
I still think that @PeterClemmensen's suggestion of using a PAGE expression makes sense. If the purpose of the exercise is to create a data set the information for which page the table is from is in the output data set in the _page_ variable (which doesn't appear in the set if a page dimension is not used).
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
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.
Ready to level-up your skills? Choose your own adventure.