BookmarkSubscribeRSS Feed
purpleclothlady
Pyrite | Level 9

 

hi all:

I would need to output multiple proc report rtf files into ONE rtf file based on whether the dataset exists or not. 

QUESTION:

  • I am not sure what is the issue with the current code.
  • how to overwrite the current RTF file if i rerun with different time

thanks so much,

C

/*===============SAS CODE=================*/

data new;
input order;
datalines;
run;

 

%macro rpt2(ds, ord);

filename myfile "C:\datacheck.rtf";

ods results off;
ods listing close;
ods escapechar="^";

ods rtf file=myfile style=LRX nogfootnote nogtitle startpage=YES;

 

title1 "t1";
title2 "t2";
title3 "t3";

 

%global TOTAL_RECORD;
%LET dsid=%SYSFUNC(OPEN(&ds.));
%LET TOTAL_RECORD=%SYSFUNC(ATTRN(&dsid.,NOBS));
%LET rc=%SYSFUNC(CLOSE(&dsid.));
%put dsid=&dsid. TOTAL_RECORD=&TOTAL_RECORD. ;

 

%IF &TOTAL_RECORD ne 0 %then %do;
%if &ord=1 %then %do;
title4 "Data1";
proc report data=&ds;
column make ;
run;
%end;


%else %if &ord=2 %then %do;
title4 "data2";
proc report data=&ds;
column name;
run;
%end;


%else %if &ord =3 %then %do;
proc report data=&ds nowd split='~' missing style(header)=[just=left];;
column subject _folder;
run;
%end;
%END;


%ELSE %DO;
data use_this_if_no_obs;
msg = 'No data captured';
run;

%if &ord=1 %then %do; title4 " data"; %end;
%else %if &ord=2 %then %do; title4 "1 questions"; %end;
%else %do; title4 " "; %end;

proc report data=use_this_if_no_obs;
column msg;
define msg/ '' center;
run;
%END;


%mend rpt2;

 

%rpt2(sashelp.carS,1);
%rpt2(sashelp.class,2);
%rpt2(new,3);

 

ods rtf close;
ods results on;
ods listing;

 

/*========================LOG ---- HAS ERROR===========*/

ERROR: At least one file associated with fileref MYFILE is still in use.
ERROR: Error in the FILENAME statement.

4 REPLIES 4
ballardw
Super User

To clearly debug macros you want to run your code with Options mprint; set before the macro execution to get more details.

 

Likely your issue is that you open the ODS destination in the first macro call and then attempt to reopen the same MYFILE locatio in the second and following Macro calls without an ODS RTF close;

In effect you have generated code that looks like:

ods rtf file=myfile;
<some report goes here>
ods rtf file=myfile;  <= this is attempting to reopen the already open ods destination
<some report goes here>
ods rtf file=myfile;
<some report goes here>

You likely also will may an issue with ODS RESULTS OFF; suppressing your output.

 

Two basic approaches would be in order depending on desire. One is to send each macro call of reports to separate RTF files, with a different name.

The other is to have one ODS RTF file=; and ods rtf close around macros or code that generates output.

You would remove these from the macro:

filename myfile "C:\datacheck.rtf";

ods results off;
ods listing close;
ods escapechar="^";

ods rtf file=myfile style=LRX nogfootnote nogtitle startpage=YES;

and then have the macro call the output code between it and an ODS RTF Close:

filename myfile "C:\datacheck.rtf";

ods results off;
ods listing close;
ods escapechar="^";

ods rtf file=myfile style=LRX nogfootnote nogtitle startpage=YES;

%rpt2 (<parameters>)
%rpt2 (<other parameters>)
%rpt2 (<different parameters>)

ods rtf close;

@purpleclothlady wrote:

 

hi all:

I would need to output multiple proc report rtf files into ONE rtf file based on whether the dataset exists or not. 

QUESTION:

  • I am not sure what is the issue with the current code.
  • how to overwrite the current RTF file if i rerun with different time

thanks so much,

C

/*===============SAS CODE=================*/

data new;
input order;
datalines;
run;

 

%macro rpt2(ds, ord);

filename myfile "C:\datacheck.rtf";

ods results off;
ods listing close;
ods escapechar="^";

ods rtf file=myfile style=LRX nogfootnote nogtitle startpage=YES;

 

title1 "t1";
title2 "t2";
title3 "t3";

 

%global TOTAL_RECORD;
%LET dsid=%SYSFUNC(OPEN(&ds.));
%LET TOTAL_RECORD=%SYSFUNC(ATTRN(&dsid.,NOBS));
%LET rc=%SYSFUNC(CLOSE(&dsid.));
%put dsid=&dsid. TOTAL_RECORD=&TOTAL_RECORD. ;

 

%IF &TOTAL_RECORD ne 0 %then %do;
%if &ord=1 %then %do;
title4 "Data1";
proc report data=&ds;
column make ;
run;
%end;


%else %if &ord=2 %then %do;
title4 "data2";
proc report data=&ds;
column name;
run;
%end;


%else %if &ord =3 %then %do;
proc report data=&ds nowd split='~' missing style(header)=[just=left];;
column subject _folder;
run;
%end;
%END;


%ELSE %DO;
data use_this_if_no_obs;
msg = 'No data captured';
run;

%if &ord=1 %then %do; title4 " data"; %end;
%else %if &ord=2 %then %do; title4 "1 questions"; %end;
%else %do; title4 " "; %end;

proc report data=use_this_if_no_obs;
column msg;
define msg/ '' center;
run;
%END;


%mend rpt2;

 

%rpt2(sashelp.carS,1);
%rpt2(sashelp.class,2);
%rpt2(new,3);

 

ods rtf close;
ods results on;
ods listing;

 

/*========================LOG ---- HAS ERROR===========*/

ERROR: At least one file associated with fileref MYFILE is still in use.
ERROR: Error in the FILENAME statement.


It is a good idea to show the code from the log that generates errors. Copy the text from the Log then on the forum open a text box using the </> icon above the message window and paste. You can see the result in the boxes around my example code above. The message windows will reformat code and error diagnostics and the text box will help see where some of the errors are. The Options MPRINT will result in the errors being closer to the actual code causing issues instead of the default of after the macro call with no details.

Cynthia_sas
SAS Super FREQ

Hi:
I tell my students that they should think of ODS statements like a sandwich (a simple sandwich) with one piece of bread on the top of the sandwich and one piece of bread on the bottom of the sandwich. If you move your initial "top" piece of bread outside of the macro invocation, then you'll only have 1 piece of bread. As it is now, with the ODS RTF statement inside the macro program, you are trying to open the RTF file over again each time you invoke the macro program.
filename myfile 'path-to-folder\allreports.rtf';
ods rtf file=myfile;
  %makerep(dsn=lettuce)
  %makerep(dsn=tomato)
  %makerep(dsn=cheese)
  %makerep(dsn=bacon)
ods rtf close;

So you might need to redesign your macro program so that you move the top piece of bread outside of the invocation of the macro program.

Microsoft Word has very strict rules about the opening RTF control strings and closing RTF control strings that need to be placed in your RTF file. The ODS RTF "top" writes the control strings needed for the top of the RTF file. When you repeat the statement with FILE=, you are essentially trying to re-establish the file and write the top strings for the second and all subsequent output, which ODS is complaining about.
Cynthia

purpleclothlady
Pyrite | Level 9

thank you very much for clarification. it works. 

purpleclothlady
Pyrite | Level 9

Thank you very much, it works.
Both of you very well explained the ODS RTF Open and Close in Multiple proc report files output to One RTF file.

/*-----------------------updated code--------------------------*/

data new;
input order;
datalines;
run;
filename  myfile "C:\DESPTOP\myfile.rtf";

 

ods results off;
/*Using ODS RESULTS ON sends all output to the SAS Results window. This is the !!default!! setting. Using ODS RESULTS OFF disables ODS tracking, and output is not sent to the Results window. */

 

ods listing close;
/*The !!default !!SAS output location is the normal “listing” which appears in the Output window. This output can be turned on using the command: ODS LISTING; and turned off using ODS LISTING CLOSE;*/


ods escapechar="^";
/**/

ods rtf file=myfile
title1 "t1";
title2 "t2";
footnote "Page ^{thispage} of ^{lastpage}";


ods rtf file=myfile
/*startpage=yes*/;
/*YES | ON Do the default startpage behavior: a new page at the start of each procedure, and in the case of a few procedures, within them, as requested by the procedure code*/
title1 "t1";
title2 "t2";
footnote "Page ^{thispage} of ^{lastpage}";

/*USE SAS SYSTEM FUNCTION TO CHECK IF A DATA SETS HAS OBS*/
%MACRO rpt2(ds, ord);


%global TOTAL_RECORD;
%LET dsid=%SYSFUNC(OPEN(&ds.));
%LET TOTAL_RECORD=%SYSFUNC(ATTRN(&dsid.,NOBS));
%LET rc=%SYSFUNC(CLOSE(&dsid.));
%put dsid=&dsid. TOTAL_RECORD=&TOTAL_RECORD. ;

/*CHECK TOTAL OBS OF THE DATASET*/
%IF &TOTAL_RECORD ne 0 %then %do;
%if &ord=1 %then %do;
title3 "Data1";
proc report data=&ds (obs=5);
column make ;
run;
%end;
%else %if &ord=2 %then %do;
title3 "data2";
proc report data=&ds;
column name;
run;
%end;
%else %if &ord =3 %then %do;
title3 "Data3";
proc report data=&ds (obs=6) nowd split='~' missing style(header)=[just=left];;
column subject _folder;
run;
%end;
%END;


%ELSE %DO;
data use_this_if_no_obs;
msg = 'No data captured';
run;
proc report data=use_this_if_no_obs;
column msg;
define msg/ '' center;
run;
%END;
%MEND rpt2;


%rpt2(sashelp.carS,1);
%rpt2(sashelp.class,2);
%rpt2(new,3);


/*CLOSE ONCE ALL 3 RTF FILES ARE CREATED*/
ods rtf close;
ods listing;

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 4 replies
  • 1859 views
  • 2 likes
  • 3 in conversation