Hello eveyone!
I use SAS Enterprise Guide 8.5 with and have been struggling with the following issue for a few days.
I run the code below:
DATA AAA; SET SASHELP.CARS; PAGE_NO = FLOOR((_n_-1)/15)+1; RUN; ODS RTF(ID=INDA) FILE= "\\app01.icrc.local\Share\Projects\ROX_795_SC-332A\Biostatistics\Prog\A.rtf" CONTENTS=YES STARTPAGE=YES TOC_DATA; PROC REPORT DATA=AAA(obs=100); COLUMNS PAGE_NO Make Model Type Origin DriveTrain MSRP Invoice EngineSize Cylinders Horsepower MPG_City MPG_Highway; DEFINE PAGE_NO / ORDER NOPRINT contents=""; DEFINE Make / ORDER NOPRINT; DEFINE Model / DISPLAY ID STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Type / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Origin / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE DriveTrain / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MSRP / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Invoice / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN} contents="" PAGE; DEFINE EngineSize / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Cylinders / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Horsepower / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_City / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_Highway /DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; COMPUTE BEFORE Make; LINE @1 " "; LINE @1 Make $16.; LINE @1 " "; ENDCOMP; break before page_no / page contents=""; compute after _page_; line "Some text"; line "Some other text"; endcomp; compute after; line "End of Table"; endcomp; RUN; ODS RTF(ID=INDA) CLOSE;
My purpose is to produce a report:
1) With page breaks (hence the line break before page_no / page);
2) With footnotes in every page and a messege in the end of table;
3) With page breakes before the column Invoice (hence DEFINE Invoice / ... PAGE);
4) With a line before every new group (hence the COMPUTE BEFORE Make block);
The problem is that the generated report has the first page empty:
Everything else works fine.
I tried some approaches. So, replacing break before page_no / page with break after page_no / page solves this problem, but creates other ones (for example empty pages in the end).
Also, deleting the COMPUTE BEFORE Make block make thing better. But unfortunately, the line before every group is required.
Of course reducing column width (so that all columns fit in one page) helps too, but in real projects we often have reports with many columns.
I hope someone could help me with good advice. Thanks in advance!
ODS TEXT='xxxxxxxx' ;
%if &level.=&last. %then %do; line " "; line "End of Table"; %end;
DATA AAA; SET SASHELP.CARS; RUN; proc sort data=AAA; by Make; run; data AAA; set AAA; PAGE_NO = FLOOR((_n_-1)/15)+1; run; proc sort data=AAA; by Make; run; proc freq data=AAA noprint; table Make/out=levels; run; %macro report(level=); PROC REPORT DATA=AAA nowd; where Make="&level."; COLUMNS PAGE_NO Make Model Type Origin DriveTrain MSRP Invoice EngineSize Cylinders Horsepower MPG_City MPG_Highway; DEFINE PAGE_NO / ORDER NOPRINT; DEFINE Make / ORDER NOPRINT; DEFINE Model / DISPLAY ID STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Type / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Origin / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE DriveTrain / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MSRP / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Invoice / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN} PAGE; DEFINE EngineSize / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Cylinders / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Horsepower / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_City / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_Highway /DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; COMPUTE BEFORE Make; LINE @1 " "; LINE @1 Make $16.; LINE @1 " "; ENDCOMP; compute after Make; line "Some text"; line "Some other text"; endcomp; break after page_no / page contents=""; RUN; %mend; ODS RTF(ID=INDA) FILE= "c:\temp\A.rtf" CONTENTS=YES STARTPAGE=NO TOC_DATA; data _null_; set levels; call execute(catt('%report(level=',Make,')')); run; ods text='End of Table'; ODS RTF(ID=INDA) CLOSE;
Or you could try wide layout by using "options orientation=" . And delete "ID" and "PAGE" option in DEFINE statement.
options orientation=landscape;
ODS RTF(ID=INDA) FILE=.........................
Interesting. You could try BY statement instead of PAGE option.
DATA AAA; SET SASHELP.CARS; PAGE_NO = FLOOR((_n_-1)/15)+1; RUN; option nobyline; ODS RTF(ID=INDA) FILE= "c:\temp\A.rtf" CONTENTS=YES STARTPAGE=YES TOC_DATA; PROC REPORT DATA=AAA(obs=100); by PAGE_NO; COLUMNS /* PAGE_NO */ Make Model Type Origin DriveTrain MSRP Invoice EngineSize Cylinders Horsepower MPG_City MPG_Highway; /* DEFINE PAGE_NO / ORDER NOPRINT ;*/ DEFINE Make / ORDER NOPRINT; DEFINE Model / DISPLAY ID STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Type / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Origin / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE DriveTrain / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MSRP / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Invoice / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN} PAGE; DEFINE EngineSize / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Cylinders / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Horsepower / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_City / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_Highway /DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; COMPUTE BEFORE Make; LINE @1 " "; LINE @1 Make $16.; LINE @1 " "; ENDCOMP; /* break before page_no / page contents="";*/ compute after _page_; line "Some text"; line "Some other text"; endcomp; compute after; line "End of Table"; endcomp; RUN; ODS RTF(ID=INDA) CLOSE;
Thanks for the idea!
But looks like it doesn't work as desired.
First, it produces the line "End of Table" on every page instead of the actual end of the table.
Second, on some pages data appear even after the footnotes.
OK. you could make a macro to workaround with this question.
DATA AAA;
SET SASHELP.CARS(obs=100);
RUN;
proc sort data=AAA;
by Make;
run;
proc freq data=AAA noprint;
table Make/out=levels;
run;
data _null_;
set levels;
call symputx('last',Make);
run;
%macro report(level=);
PROC REPORT DATA=AAA;
where Make="&level.";
COLUMNS Make Model Type Origin DriveTrain MSRP Invoice EngineSize Cylinders Horsepower MPG_City MPG_Highway;
DEFINE Make / ORDER NOPRINT;
DEFINE Model / DISPLAY ID STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE Type / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE Origin / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE DriveTrain / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE MSRP / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE Invoice / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN} PAGE;
DEFINE EngineSize / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE Cylinders / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE Horsepower / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE MPG_City / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
DEFINE MPG_Highway /DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN};
COMPUTE BEFORE Make;
LINE @1 " ";
LINE @1 Make $16.;
LINE @1 " ";
ENDCOMP;
compute after _page_;
line "Some text";
line "Some other text";
endcomp;
%if &level.=&last. %then %do;
compute after;
line "End of Table";
endcomp;
%end;
RUN;
%mend;
ODS RTF(ID=INDA) FILE= "c:\temp\A.rtf" CONTENTS=YES STARTPAGE=YES TOC_DATA;
data _null_;
set levels;
call execute(catt('%report(level=',Make,')'));
run;
ODS RTF(ID=INDA) CLOSE;
"compute after " would execute before "compute after _page_" , you would get reverse order of text , try to combine them together.
DATA AAA; SET SASHELP.CARS(obs=200); RUN; proc sort data=AAA; by Make; run; proc freq data=AAA noprint; table Make/out=levels; run; data _null_; set levels; call symputx('last',Make); run; %macro report(level=); PROC REPORT DATA=AAA nowd; where Make="&level."; COLUMNS Make Model Type Origin DriveTrain MSRP Invoice EngineSize Cylinders Horsepower MPG_City MPG_Highway; DEFINE Make / ORDER NOPRINT; DEFINE Model / DISPLAY ID STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Type / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Origin / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE DriveTrain / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MSRP / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Invoice / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN} PAGE; DEFINE EngineSize / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Cylinders / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Horsepower / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_City / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_Highway /DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; COMPUTE BEFORE Make; LINE @1 " "; LINE @1 Make $16.; LINE @1 " "; ENDCOMP; compute after _page_; line "Some text"; line "Some other text"; %if &level.=&last. %then %do; line " "; line "End of Table"; %end; endcomp; RUN; %mend; ODS RTF(ID=INDA) FILE= "c:\temp\A.rtf" CONTENTS=YES STARTPAGE=YES TOC_DATA; data _null_; set levels; call execute(catt('%report(level=',Make,')')); run; ODS RTF(ID=INDA) CLOSE;
Thanks for your effort!
But there's still some issues.
First, the line 'End of Table' is seen on the two last pages instead of only the last one.
Besides, for groups with few entries thewe will be pages with too much empty space, whereas groups with too many entries would cause other problems. This why controlled page breaks are important here.
@RooRoo wrote:
Thanks for your effort!
But there's still some issues.
First, the line 'End of Table' is seen on the two last pages instead of only the last one.
Besides, for groups with few entries thewe will be pages with too much empty space, whereas groups with too many entries would cause other problems. This why controlled page breaks are important here.
Hint: when trying to create an exact appearance then provide an example of what the desired appearance actually is, as in a manually created document. That way we can tell if the result of a code suggestion does not actually meet requirement. Without a clear requirement you will get many "close but not quite" because we don't know the actual requirement.
ODS TEXT='xxxxxxxx' ;
%if &level.=&last. %then %do; line " "; line "End of Table"; %end;
DATA AAA; SET SASHELP.CARS; RUN; proc sort data=AAA; by Make; run; data AAA; set AAA; PAGE_NO = FLOOR((_n_-1)/15)+1; run; proc sort data=AAA; by Make; run; proc freq data=AAA noprint; table Make/out=levels; run; %macro report(level=); PROC REPORT DATA=AAA nowd; where Make="&level."; COLUMNS PAGE_NO Make Model Type Origin DriveTrain MSRP Invoice EngineSize Cylinders Horsepower MPG_City MPG_Highway; DEFINE PAGE_NO / ORDER NOPRINT; DEFINE Make / ORDER NOPRINT; DEFINE Model / DISPLAY ID STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Type / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Origin / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE DriveTrain / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MSRP / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Invoice / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN} PAGE; DEFINE EngineSize / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Cylinders / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Horsepower / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_City / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_Highway /DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; COMPUTE BEFORE Make; LINE @1 " "; LINE @1 Make $16.; LINE @1 " "; ENDCOMP; compute after Make; line "Some text"; line "Some other text"; endcomp; break after page_no / page contents=""; RUN; %mend; ODS RTF(ID=INDA) FILE= "c:\temp\A.rtf" CONTENTS=YES STARTPAGE=NO TOC_DATA; data _null_; set levels; call execute(catt('%report(level=',Make,')')); run; ods text='End of Table'; ODS RTF(ID=INDA) CLOSE;
And I also found you could get job done with your original code by this one:
DATA AAA; SET SASHELP.CARS; RUN; proc sort data=AAA; by Make; run; data AAA; set AAA; PAGE_NO = FLOOR((_n_-1)/15)+1; run; ODS RTF(ID=INDA) FILE= "c:\temp\A.rtf" CONTENTS=YES STARTPAGE=YES TOC_DATA; PROC REPORT DATA=AAA(obs=100); COLUMNS PAGE_NO Make Model Type Origin DriveTrain MSRP Invoice EngineSize Cylinders Horsepower MPG_City MPG_Highway; DEFINE PAGE_NO / ORDER NOPRINT contents=""; DEFINE Make / ORDER NOPRINT; DEFINE Model / DISPLAY ID STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Type / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Origin / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE DriveTrain / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MSRP / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Invoice / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN} contents="" PAGE; DEFINE EngineSize / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Cylinders / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE Horsepower / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_City / DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; DEFINE MPG_Highway /DISPLAY STYLE(COLUMN)={CELLWIDTH=1IN}; COMPUTE BEFORE Make; LINE @1 " "; LINE @1 Make $16.; LINE @1 " "; ENDCOMP; break after page_no / page contents=""; compute after _page_; line "Some text"; line "Some other text"; endcomp; RUN; ods text='End of Table'; ODS RTF(ID=INDA) CLOSE;
That works fine, thank you!
But I just discovered something strange. I noticed there's two "first" pages. All further pages are numerated correctly.
Besides, in TOC there's unwanted Table1 which appears when using break after page_no / page contents=""; instead of break before page_no / page contents="";
Do you have any ideas?
Actually I did not get any problem.
But if you really have this problem , you can use ~{thispage} to get the page number:
option nodate nonumber; ODS RTF(ID=INDA) FILE= "c:\temp\A.rtf" CONTENTS=YES STARTPAGE=YES TOC_DATA; title j=r "Page(*ESC*){thispage}"; PROC REPORT DATA=AAA(obs=100);
About your last question, I have no idea. Maybe @Cynthia_sas would give you a hand.
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9.
Early bird rate extended! Save $200 when you sign up by March 31.
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.