Previous Page | Next Page

Writing Lines to the SAS Log or to an Output File

Writing a Report


Writing to an Output File

The PUT statement writes lines of text to the SAS log. However, the SAS log is not usually a good destination for a formal report because it also contains the source statements for the program and messages from SAS.

The simplest destination for a printed report is the SAS output file, which is the same place SAS writes output from procedures. SAS automatically defines various characteristics such as page numbers for the procedure output file, and you can take advantage of them instead of defining all the characteristics yourself.

To route lines to the procedure output file, use the FILE statement. The FILE statement has the following form:

FILE PRINT <options>;

PRINT is a reserved fileref that directs output that is produced by PUT statements to the same print file as the output that is produced by SAS procedures.

Note:   Be sure that the FILE statement precedes the PUT statement in the program code.  [cautionend]

FILE statement options specify options that you can use to customize output. The report that is produced in this section uses the following options:

NOTITLES

eliminates the default title line and makes that line available for writing. By default, the procedure output file contains the title "The SAS System." Because the report creates another title that is descriptive, you can remove the default title by specifying the NOTITLES option.

FOOTNOTES

controls whether currently defined footnotes are written to the report.

Note:   When you use the FILE statement to include footnotes in a report, you must use the FOOTNOTES option in the FILE statement and include a FOOTNOTE statement in your program. The FOOTNOTE statement contains the text of the footnote.  [cautionend]

Note:   You can also remove the default title with a null TITLE statement: title; . In this case, SAS writes a line that contains only the date and page number in place of the default title, and the line is not available for writing other text.  [cautionend]


Designing the Report

After choosing a destination for your report, the next step in producing a report is to decide how you want it to look. You create the design and determine which lines and columns the text will occupy. Planning how you want your final report to look helps you write the necessary PUT statements to produce the report. The rest of the examples in this section show how to modify a program to produce a final report that resembles the one shown here.

----+----1----+----2----+----3----+----4----+----5----+----6----+----7--
 1             Morning and Evening Newspaper Circulation
 2
 3    State              Year                     Thousands of Copies
 4                                                Morning      Evening
 5
 6    Alabama            1984                       256.3        480.5
 7                       1985                       291.5        454.3
 8                       1986                       303.6        454.7
 9                       1987                          .         454.5
10                                                  ------      -------
11                       Total for each category    851.4       1844.0
12                                Combined total          2695.4
13
14
15    Massachusetts      1984                          .            . 
16                       1985                          .          68.0
17                       1986                       222.7         68.6
18                       1987                       224.1         66.7
19                                                 ------        ------
20                       Total for each category    446.8        203.3
21                                Combined total           650.1
22
23
24
25
26
27
28
29
30                         Preliminary Report
----+----1----+----2----+----3----+----4----+----5----+----6----+----7--


Writing Data Values

After you design your report, you can begin to write the program that will create it. The following program shows how to display the data values for the YEAR, MORNING_COPIES, and EVENING_COPIES variables in specific positions.

In a PUT statement, the @ followed by a number is a pointer control, but it is different from the trailing @ described earlier. The @n argument is a column-pointer control. It tells SAS to move to column n. In this example the pointer moves to the specified locations, and the PUT statement writes values at those points using list output. Combining list output with pointer controls is a simple but useful way of writing data values in columns.

options pagesize=30 linesize=80 pageno=1 nodate;

data _null_;
   infile 'your-input-file';
   input state $ morning_copies evening_copies year;
   file print notitles;
   put @26 year @53 morning_copies @66 evening_copies;
run;

The following output shows the results:

Data Values in Specific Locations in the Output

                         1999                       798.4        984.7
                         1998                       834.2        793.6
                         1997                       750.3        .
                         1999                       .            698.4
                         1998                       463.8        522
                         1997                       583.2        234.9
                         1996                       .            339.6

Improving the Appearance of Numeric Data Values

In the design for your report, all numeric values are aligned on the decimal point (see Data Values in Specific Locations in the Output). To achieve this result, you have to alter the appearance of the numeric data values by using SAS formats. In the input data all values for MORNING_COPIES and EVENING_COPIES contain one decimal place, except in one case where the decimal value is 0. In list output SAS writes values in the simplest way, that is, by omitting the 0s in the decimal portion of a value. In formatted output, you can show one decimal place for every value by associating a format with a variable in the PUT statement. Using a format can also align your output values.

The format that is used in the program is called the w.d format. The w.d format specifies the number of columns to be used for writing the entire value, including the decimal point. It also specifies the number of columns to be used for writing the decimal portion of each value. In this example the format 5.1 causes SAS to use five columns, including one decimal place, for writing each value. Therefore, SAS prints the 0s in the decimal portion as necessary. The format also aligns the periods that SAS uses to indicate missing values with the decimal points.

options pagesize=30 linesize=80 pageno=1 nodate;

data _null_;
   infile 'your-input-file';
   input state $ morning_copies evening_copies year;
   file print notitles;
   put @26 year @53 morning_copies 5.1 @66 evening_copies 5.1;
run;

The following output shows the results:

Formatted Numeric Output

                         1999                       798.4        984.7
                         1998                       834.2        793.6
                         1997                       750.3           .
                         1999                          .         698.4
                         1998                       463.8        522.0
                         1997                       583.2        234.9
                         1996                          .         339.6

Writing a Value at the Beginning of Each BY Group

The next step in creating your report is to add the name of the state to your output. If you include the name of the state in the PUT statement with other data values, then the state will appear on every line. However, remembering what you want your final report to look like, you need to write the name of the state only for the first observation of a particular state. Performing a task once for a group of observations requires the use of the BY statement for BY-group processing. The BY statement has the following form:

BY by-variable(s)<NOTSORTED>;

The by-variable names the variable by which the data set is sorted. The optional NOTSORTED option specifies that observations with the same BY value are grouped together but are not necessarily sorted in alphabetical or numerical order.

For BY-group processing,

The following program creates a permanent SAS data set named NEWS.CIRCULATION, and writes the name of the state on the first line of the report for each BY group.

options pagesize=30 linesize=80 pageno=1 nodate;

libname news 'SAS-data-library';
data news.circulation;
   length state $ 15;
   input state $ morning_copies evening_copies year;
   datalines;
Massachusetts 798.4 984.7 1999
Massachusetts 834.2 793.6 1998
Massachusetts 750.3 .     1997
Alabama       .     698.4 1999
Alabama       463.8 522.0 1998
Alabama       583.2 234.9 1997
Alabama       .     339.6 1996
;

data _null_;
   set news.circulation;
   by state notsorted;
   file print notitles;
   if first.state then put / @7 state @;
   put @26 year @53 morning_copies 5.1 @66 evening_copies 5.1;
run;

During the first observation for a given state, a PUT statement writes the name of the state and holds the line for further writing (the year and circulation figures). The next PUT statement writes the year and circulation figures and releases the held line. In observations after the first, only the second PUT statement is processed. It writes the year and circulation figures and releases the line as usual.

The first PUT statement contains a slash (/), a pointer control that moves the pointer to the beginning of the next line. In this example, the PUT statement prepares to write on a new line (the default action). Then the slash moves the pointer to the beginning of the next line. As a result, SAS skips a line before writing the value of STATE. In the output, a blank line separates the data for Massachusetts from the data for Alabama. The output for Massachusetts also begins one line farther down the page than it would have otherwise. (That blank line is used later in the development of the report.)

The following output shows the results:

Effect of BY-Group Processing

      Massachusetts      1999                       798.4        984.7
                         1998                       834.2        793.6
                         1997                       750.3           .

      Alabama            1999                          .         698.4
                         1998                       463.8        522.0
                         1997                       583.2        234.9
                         1996                          .         339.6

Calculating Totals

The next step is to calculate the total morning circulation figures, total evening circulation figures, and total overall circulation figures for each state. Sum statements accumulate the totals, and assignment statements start the accumulation at 0 for each state. When the last observation for a given state is being processed, an assignment statement calculates the overall total, and a PUT statement writes the totals and additional descriptive text.

options pagesize=30 linesize=80 pageno=1 nodate;
libname news 'SAS-data-library';

data _null_;
   set news.circulation;
   by state notsorted;
   file print notitles;
      /* Set values of accumulator variables to 0 */
      /* at beginning of each BY group.           */
      if first.state then
         do;
            morning_total=0;
            evening_total=0;
            put / @7 state @;
         end;
   put @26 year @53 morning_copies 5.1 @66 evening_copies 5.1;

      /* Accumulate separate totals for morning and */
      /* evening circulations.                      */
   morning_total+morning_copies;
   evening_total+evening_copies;

      /* Calculate total circulation at the end of  */
      /* each BY group.                             */

   if last.state then
      do;      
         all_totals=morning_total+evening_total;      
         put @52 '------' @65 '------' /            
             @26 'Total for each category'
             @52 morning_total 6.1 @65 evening_total 6.1 / 
             @35 'Combined total' @59 all_totals 6.1;    
      end;
run;

The following output shows the results:

Calculating and Writing Totals for Each BY Group

      Massachusetts      1999                       798.4        984.7
                         1998                       834.2        793.6
                         1997                       750.3           .
                                                   ------       ------
                         Total for each category   2382.9       1778.3
                                  Combined total          4161.2

      Alabama            1999                          .         698.4
                         1998                       463.8        522.0
                         1997                       583.2        234.9
                         1996                          .         339.6
                                                   ------       ------
                         Total for each category   1047.0       1794.9
                                  Combined total          2841.9

Notice that Sum statements ignore missing values when they accumulate totals. Also, by default, Sum statements assign the accumulator variables (in this case, MORNING_TOTAL and EVENING_TOTAL) an initial value of 0. Therefore, although the assignment statements in the DO group are executed for the first observation for both states, you need them only for the second state.


Writing Headings and Footnotes for a One-Page Report

The report is complete except for the title lines, column headings, and footnote. Because this is a simple, one-page report, you can write the heading with a PUT statement that is executed only during the first iteration of the DATA step. The automatic variable _N_ counts the number of times the DATA step has iterated or looped, and the PUT statement is executed when the value of _N_ is 1.

The FOOTNOTES option on the FILE statement and the FOOTNOTE statement create the footnote. The following program is complete:

options pagesize=30 linesize=80 pageno=1 nodate;
libname news 'SAS-data-library';

data _null_;
   set news.circulation;
   by state notsorted;
   file print notitles footnotes;
   if _n_=1 then put @16 'Morning and Evening Newspaper Circulation' //
                     @7  'State' @26 'Year' @51 'Thousands of Copies' /
                     @51 'Morning      Evening'; 
   if first.state then
      do;
         morning_total=0;
         evening_total=0;
         put / @7 state @;
      end;
   put @26 year @53 morning_copies 5.1 @66 evening_copies 5.1;
   morning_total+morning_copies;
   evening_total+evening_copies;
   if last.state then
      do;
         all_totals=morning_total+evening_total;
         put @52 '------' @65 '------' /
             @26 'Total for each category'
             @52 morning_total 6.1 @65 evening_total 6.1 /
             @35 'Combined total' @59 all_totals 6.1;
      end;
   footnote 'Preliminary Report';
run;

The following output shows the results:

The Final Report

               Morning and Evening Newspaper Circulation

      State              Year                     Thousands of Copies
                                                  Morning      Evening

      Massachusetts      1999                       798.4        984.7
                         1998                       834.2        793.6
                         1997                       750.3           .
                                                   ------       ------
                         Total for each category   2382.9       1778.3
                                  Combined total          4161.2

      Alabama            1999                          .         698.4
                         1998                       463.8        522.0
                         1997                       583.2        234.9
                         1996                          .         339.6
                                                   ------       ------
                         Total for each category   1047.0       1794.9
                                  Combined total          2841.9










                               Preliminary Report

Notice that a blank line appears between the last line of the heading and the first data for Massachusetts although the PUT statement for the heading does not write a blank line. The line comes from the slash (/) in the PUT statement that writes the value of STATE in the first observation of each BY group.

Executing a PUT statement during the first iteration of the DATA step is a simple way to produce headings, especially when a report is only one page long.

Previous Page | Next Page | Top of Page