Writing Lines to the SAS Log or to an Output File |
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.
FILE statement options specify options that you can use to customize output. The report that is produced in this section uses the following options:
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.
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.
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.
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:
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.
ensure that observations come from a SAS data set, not an external file.
when the data is grouped in BY groups but the groups are not necessarily in alphabetical order, use the NOTSORTED option in the BY statement. For example, use
by state notsorted;
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:
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:
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.
Copyright © 2012 by SAS Institute Inc., Cary, NC, USA. All rights reserved.