Creating DATA Step Reports with the LISTING

Creating DATA Step
Reports with the LISTING
Destination
Transcript
Creating DATA Step Reports with the LISTING Destination Transcript was developed by Linda
Mitterling. Additional contributions were made by David Ghan, Lorilyn Russell, Jason Secosky, and
Cynthia Zender. Editing and production support was provided by the Curriculum Development and
Support Department.
SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of
SAS Institute Inc. in the USA and other countries. ® indicates USA registration. Other brand and product
names are trademarks of their respective companies.
Creating DATA Step Reports with the LISTING Destination Transcript
Copyright © 2009 SAS Institute Inc. Cary, NC, USA. All rights reserved. Printed in the United States of
America. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in
any form or by any means, electronic, mechanical, photocopying, or otherwise, without the prior written
permission of the publisher, SAS Institute Inc.
Book code E1382, course code RLSPDSL, prepared date 26Jan2009.
RLSPDSL_001
ISBN 978-1-59994-879-9
For Your Information
Table of Contents
Lecture Description ..................................................................................................................... iv Prerequisites ................................................................................................................................. v Creating DATA Step Reports with the LISTING Destination........................................ 1 1.
Introduction to DATA Step Reporting ................................................................................ 5 2.
Creating Simple Listing Reports ....................................................................................... 15 3.
Enhancing Reports ............................................................................................................ 32 4.
Creating Summary Reports ............................................................................................... 57 5.
Creating Multicolumn Reports ......................................................................................... 64 Appendix A
Lecture and Demonstration Code ...................................................... A-1 1.
Creating a Simple Listing Report ................................................................................... A-3 2.
Creating Headers and Footers ......................................................................................... A-4 3.
Adding Page Numbers and Run Date ............................................................................. A-5 iii
iv
For Your Information
Lecture Description
This lecture addresses how to use the DATA step to send reports to the LISTING destination. Specifically,
this lecture shows how to use the DATA step to create simple listing reports, add enhancements to reports
(headers and footers, subtotals and grandtotals), and create a summary report, and how to create a
multicolumn report.
To learn more…
For information on other courses in the curriculum, contact the SAS Education
Division at 1-800-333-7660, or send e-mail to [email protected]. You can also
find this information on the Web at support.sas.com/training/ as well as in the
Training Course Catalog.
For a list of other SAS books that relate to the topics covered in this
Course Notes, USA customers can contact our SAS Publishing Department at
1-800-727-3228 or send e-mail to [email protected]. Customers outside the
USA, please contact your local SAS office.
Also, see the Publications Catalog on the Web at support.sas.com/pubs for a
complete list of books and a convenient order form.
For Your Information
Prerequisites
Before viewing this lecture, you should have completed the SAS® Programming 1: Essentials course or
have equivalent experience. Specifically, you should be able to
• control DATA step logic using IF-THEN/ELSE statements and logical operators
• use the FORMAT procedure to create temporary custom formats.
v
vi
For Your Information
Creating DATA Step Reports with the
LISTING Destination
1. Introduction to DATA Step Reporting .............................................................................. 5 2. Creating Simple Listing Reports .................................................................................... 15 3. Enhancing Reports .......................................................................................................... 32 4. Creating Summary Reports ............................................................................................ 57 5. Creating Multicolumn Reports ....................................................................................... 64 2
Creating DATA Step Reports with the LISTING Destination
1. Introduction to DATA Step Reporting
3
Creating DATA Step Reports
with the LISTING Destination
Welcome to this SAS e-Lecture entitled Creating DATA Step Reports with the LISTING Destintation. My
name is Linda and I am an instructor for SAS.
4
Creating DATA Step Reports with the LISTING Destination
Creating DATA Step Reports with the LISTING Destination
1. Introduction to DATA Step Reporting
2. Creating Simple Listing Reports
3. Enhancing Reports
4. Creating Summary Reports
5. Creating Multicolumn Reports
2
These are the topics that we will be covering in this e-lecture. But before I cover the information in this
slide, I just want to make sure that you are clear on the intent of this lecture. This lecture is about sending
reports to the LISTING destination, not about formatting reports with the Output Delivery System. This
e-lecture only covers the LISTING destination and free-format reports. We have another e-lecture entitled
Creating DATA Step Reports in the Output Delivery System if you want to know more about formatting
reports with ODS. With all of this in mind, let’s continue.
In the first section, we will look at some of the types of reports that can be created using the DATA step.
In the second section, we will create a very simple listing report that we will build on for later examples.
In Section 3, we will add enhancements to our reports, for example, headers and footers, and subtotals
and grandtotals.
In Section 4, we will take a look at creating a summary report that would be difficult to create in other
places in SAS.
And finally, in Section 5, we will look at creating a multicolumn report.
1. Introduction to DATA Step Reporting
1.
Introduction to DATA Step Reporting
Creating DATA Step Reports with the LISTING Destination
1. Introduction to DATA Step Reporting
2. Creating Simple Listing Reports
3. Enhancing Reports
4. Creating Summary Reports
5. Creating Multicolumn Reports
3
Let’s get started with the first section.
5
6
Creating DATA Step Reports with the LISTING Destination
Objectives
„
Explain the types of reports that can be created using
the DATA step.
„
Define the LISTING destination.
4
In this section we will look at the types of reports that you can create using the DATA step in the
LISTING destination. We will also look at what we mean by sending reports to the LISTING destination.
1. Introduction to DATA Step Reporting
7
Defining the Output Delivery System
Reports that you produce are sent to the Output Delivery System.
LISTING
Procedure
Output
DATA Step
Reports
Output
Delivery
System
HTML
RTF
PDF
5
Now, when you produce reports in SAS through the DATA step or procedures, the reports are sent to the
Output Delivery System, or ODS. ODS can then send your report to various output destinations, such as
the LISTING destination or an HTML file or PDF file. If you don’t need control over formatting such as
font style, font colors, line styles and such, then you would send your output to the LISTING destination.
If you do want to control formatting features and you want to take advantage of features that different
output destinations offer, such as RTF, PDF, or HTML, then you can tell ODS to send your output in that
direction.
In this lecture we will create LISTING output. The default ODS output type depends on where you are
working in SAS. Here, we will be working in an interactive SAS session where the LISTING destination
is the default, and the output is displayed in the Output window, and so we will not need any ODS options
or statements or the like to produce the LISTING output.
Furthermore, our concern will not be with colors or fonts or other such attributes that are supported in
ODS destinations, like PDF, RTF, and HTML, but not in LISTING output. LISTING output is plain text,
and our concern will be with how to control the placement of items on the pages of our reports.
Well, what kinds of reports are we talking about being able to create in the LISTING destination with the
DATA step?
8
Creating DATA Step Reports with the LISTING Destination
Example Reports
The DATA step can create
„
simple listing reports
6
We can create listing-style reports similar to this one. We mean two things by the term listing style.
• First, we mean that the output is very plain and unformatted.
• Secondly, we mean that this report is, literally, a list (or listing) of a job title and salaries for these job
titles.
A report similar to this could be generated with PROC PRINT, PROC REPORT, or other types of SAS
procedures. However, our purpose is to focus on using a DATA step program to generate this specific
report.
1. Introduction to DATA Step Reporting
Example Reports
„
multiline reports
Represents one
observation in the input
data set
7
Here we have created a multiline report with the DATA step, where each observation is printed on more
than one line. Notice the symbol beside the fourth observation on the report and the footnote indicating
that this person has been employed for more than 20 years. To create this report, we used conditional IF
logic. Again, there are other techniques that could be used to generate a similar report, but the report
might not look exactly the same as it does in this display. Some of those techniques (such as using a
custom TABLE template or a custom PROC REPORT step) fall outside the scope of this e-lecture.
Therefore, because our requirement was to produce exactly this report, we will create it using the DATA
step and we will send it to the LISTING destination.
9
10
Creating DATA Step Reports with the LISTING Destination
Example Reports
„
summary reports
8
Summary reports can also be created using the DATA step. A summary report, such as this one, would be
impossible to re-create using procedures in SAS. The statistics could be created easily using procedures,
but if this report layout is what you want, and you are okay with the plain listing look and feel, then the
DATA step gives the flexibility that you need to place items on the report where you want them.
1. Introduction to DATA Step Reporting
11
Example Reports
„
multicolumn reports
①
③
②
➃
9
This multicolumn report, where the observations flow from left to right instead of in a column or tabular
up-and-down form, could not be created anywhere in SAS except in the DATA step and the LISTING
destination.
12
Creating DATA Step Reports with the LISTING Destination
LISTING Destination Reports
Summary
Simple Listing
10
Multiline
Multicolumn
In this e-lecture, our goal will be to create the DATA step reports that you just saw, and we will send
them to the LISTING destination.
1. Introduction to DATA Step Reporting
Learning More About Creating ODS Reports
To learn about sending DATA step reports to other ODS destinations,
please view our e-lecture entitled:
Creating DATA Step Reports in the Output Delivery System
11
Again, if you would want to learn more about creating DATA step reports and sending them to other
ODS destinations where you can control formatting features, view the SAS e-Lecture entitled Creating
DATA Step Reports in the Output Delivery System.
13
14
Creating DATA Step Reports with the LISTING Destination
Learning More About Creating ODS Reports
The following course discusses ODS in detail:
SAS® Report Writing 1: Using Procedures and ODS
12
And to learn more about ODS in more detail, please consider our classroom or Live Web course entitled
®
SAS Report Writing 1: Using Procedures and ODS.
2. Creating Simple Listing Reports
2.
Creating Simple Listing Reports
Creating DATA Step Reports with the LISTING Destination
1. Introduction to DATA Step Reporting
2. Creating Simple Listing Reports
3. Enhancing Reports
4. Creating Summary Reports
5. Creating Multicolumn Reports
13
Now that we’ve seen the types of reports that you can create using the DATA step, and you understand
that this lecture is sending reports to the LISTING destination, let’s start building a simple LISTING
destination-style report that we will later build on to create more complex reports.
15
16
Creating DATA Step Reports with the LISTING Destination
Objectives
„
Specify the components needed to create a DATA step report
to be sent to the LISTING destination.
„
Examine the default pointer movement.
„
Examine ways to take control of column and line pointers.
„
Investigate formatting issues when using the PUT statement
to generate DATA step reports.
14
We hope to accomplish the following objectives in this section. We will
• outline the basic parts needed to produce a DATA step report,
• discuss pointer movement in the output buffer, and
• examine how to control the columns and lines that SAS writes to the output destination.
2. Creating Simple Listing Reports
Basic Steps for Creating DATA Step Reports
A typical report DATA step program contains four parts:
1. Invoke the programming environment.
2. Read data from an existing SAS data set or from an external
data source.
3. Direct the output to the standard SAS output location.
4. Write the output line.
15
A typical DATA step program for generating a report contains the four components listed here. Notice
that each of these components corresponds to a statement or statements within a DATA step program.
17
18
Creating DATA Step Reports with the LISTING Destination
Invoking the Programming Environment
1.
A DATA statement invokes the programming environment.
General form of the DATA _NULL_ statement:
DATA _NULL_;
16
Let’s take a closer look at each of these DATA step components for report writing.
The first component is the DATA statement. The DATA statement begins the DATA step and usually
identifies one or more SAS data sets that the step will create. Use the keyword _NULL_ as the data set
name when you want to create output other than a SAS data set.
Common uses for a DATA _NULL_ step are to create a report or a macro variable. In essence, you are
saying that you want to use the DATA step for some purpose, but that purpose is not to create a SAS data
set. If you don’t need to create a data set, then this technique saves I/O time and disk space.
2. Creating Simple Listing Reports
19
Reading the Data
2.
Use the appropriate statement(s) to read data from
a SAS data set or raw data file.
General form of the SET, INFILE, and INPUT statements:
SET SAS-data-set;
INFILE 'file-specification';
INPUT pointer-controls variables informats;
17
Next you must identify the source of input that will be used to generate the report and to control which
data values need to be read to create the report. If the input data source is an existing SAS data set, then a
SET statement will be used.
If the input source is an external (raw) data file, then the location of the file will be specified in an
INFILE statement, and the INPUT statement will be used to tell SAS which data values are to be read or
input.
20
Creating DATA Step Reports with the LISTING Destination
Pointing to the Output File
3.
A FILE statement directs the output to the special file reference
for output.
General form of the FILE statement:
FILE PRINT NOTITLES;
18
Then the FILE statement is used to direct the program output to a destination. We will be directing our
program output to the default LISTING destination. To specify this destination, use the PRINT argument
in the FILE statement. This keyword, PRINT, causes SAS to write the program output to a standard SAS
output file.
• On the mainframe, you might refer to this standard output file as SYSOUT or SYSPRINT.
• In an interactive session, we are pointing to the LISTING destination or OUTPUT window.
• On a UNIX system or in a batch submission, we might be pointing to the .LST file that SAS creates
when a program is submitted in batch.
Consult the documentation for your operating system for more information about this reserved file
reference.
We have also specified the NOTITLES option here. The NOTITLES option suppresses all titles from
displaying, that is, the default SAS title or titles that you might have created during this session.
2. Creating Simple Listing Reports
21
Writing to the Output Destination
4.
A PUT statement writes lines to the report.
General form of the PUT statement:
PUT pointer-controls variables formats 'literals';
19
The PUT statement does two things:
• It tells SAS what to write to the report (text or variable values).
• For the LISTING destination, it tells SAS where on the report page the information should be written.
The PUT statement causes output information to be written to the FILE PRINT location.
When directing output to the LISTING destination with FILE PRINT and PUT statements, SAS treats
your page as though it were a piece of graph paper and every letter and number that you write will use
one cell or print position on the graph paper. This means that you can position your LISTING destination
output with great certainty that position 5 will always be this position on the output page.
22
Creating DATA Step Reports with the LISTING Destination
Examining a Simple DATA Step Program
libname orion 's:\workshop';
data _null_;
set orion.employees;
where employee_country in('AU','IT','FR','US')
and department='Administration';
file print notitles;
put @5 employee_country $2. @15 job_title $25.
@40 salary dollar14.2;
run;
20
@5
@15
@40
Putting it all together… Here is a simple DATA step that creates a simple listing report.
• The LIBNAME statement points to a permanent SAS data library where the SAS data sets for our
reports reside.
• Our DATA statement says "do not create a SAS data set as the result of this DATA step."
• The SET statement says that an existing data set named orion.employees is to be used as input for
our report.
• The WHERE statement is a way to limit the observations read from orion.employees to only the
Administration departments for Australia, Italy, France, and the United States. I can use a WHERE
statement here because my input source is a SAS data set. If my input source were an external file, a
raw data file, I would be using INFILE and INPUT statements here instead of a SET statement, and I
would use an IF statement to subset my data instead of a WHERE statement.
• The FILE statement says "send the output to the default output destination."
• Finally, the PUT statement directs the placement of data values in the lines of the report.
• Take a look at the PUT statement. This PUT statement outputs the values of
employee_country starting at column 5, and the $2. instruction says to write the values in two
columns, those being columns 5 and 6.
• Then, the $25. format instructs SAS to output job_title values starting in column 15 through the
next 25 columns. Not all of the values require a width of 25. If a value is less than 25 in length and it
is a character variable, then the values are left-justified within the width that is specified, as you see
here.
2. Creating Simple Listing Reports
• Starting in column 40, the values of salary are written. The variable salary is numeric.
Therefore, if its values are shorter than the width that is specified, the values will be right-justified
within that specified width, as you can see here.
23
24
Creating DATA Step Reports with the LISTING Destination
Formatting Variable Values
How does SAS resolve formatting issues?
Format width > data value
Format width < data value
Character value – left-aligned
Character value – truncated on right
Numeric value – right-aligned
Numeric value – BESTw.d applied
You can add an alignment specification to a format:
-L left-aligns
-C centers
-R right-aligns
21
Let’s talk about justification a bit more. Specifically, what does SAS do if you specify a format width that
does not exactly fit the data values that are being formatted?
As you saw on the last screen, the PUT statement handles format widths for numeric and character values
in different ways. As this table illustrates:
If the format width is larger than the data value,
• character values are left-aligned in the field
• numeric values are right-aligned in the field.
If the format width is smaller than the data value,
• character values are truncated on the right
• the BESTw.d format is used for numeric values.
Also, you can control how a value is displayed within its formatted width by specifying alignment
options. To left-justify a data value, use the –L specification. Use –C to center values and –R to rightjustify values. Where is this specification placed in a SAS program?
2. Creating Simple Listing Reports
25
Using Alignment Specifications
Desired Results:
1
2
5 6 7 8 9 0 1 2 3 4 5 6
S e c u r i
t
y
S e c r e t
C l
3
7 8 9 0 1 2 3 4 5 6 7 8 9
G u a r d
a r y
e r k
I
I
I
I
The alignment specification is placed next to the format to which it applies.
22
put @5 employee_country $2.
@15 job_title $25. -C
@40 salary dollar14.2;
In the PUT statement, you place the format modifier (the –C in this case) next to the format ($25.) to
which it applies. In this example, SAS will output the character values of job_title with a formatted
width of 25. This means that 25 "print positions" on the page will be used to display the values. If the
value of job_title is Clerk I, the value will be centered within a width of 25, because of the –C
format modifier, as you see here.
26
Creating DATA Step Reports with the LISTING Destination
Controlling the Pointer Position
Column pointer controls:
@n
positions the pointer to column n on the current line.
+n
moves the pointer n spaces to the right from its current
location.
1 2 3 4 5 6
U S
1
7 8 9 0 1 2 3
4 5 6 7 8 9
C l
e r
2
0 1 2 3 4 5
k
I
put @5 employee_country $2. +8 job_title $25.
@40 salary dollar14.2;
23
The value of n can be a numeric value, a constant, or an
expression.
Up to this point, when we wanted the pointer to move a specific number of columns, we used what is
called an absolute pointer control, that is, the @ sign. It tells SAS to take the pointer, wherever it is, and
absolutely move it to the specified column. In the example here, I am saying absolutely take the pointer,
wherever it is right now, and move it to column number 5 and write out the values of
employee_country. There is another pointer control that I can use in the PUT statement to control
the movement of the pointer. It is called a relative pointer control and you specify it with a plus (+) sign.
I am using a relative pointer control for job_title in this example. I know that all of my
employee_country values are exactly a length of 2, for example, US, AU, FR, and others. After SAS
writes the employee_country value in columns 5 and 6, the pointer is resting in column 7. Now I
want the pointer to move to column 15. In previous examples, I said @15 job_title, but this time,
I’m going to use a relative pointer control and instruct SAS as follows: "Relative to where you are right
now in column 7, move over eight columns," (which makes it move to column 15) "and output the values
of job_title."
Either pointer control, the @ or the +, will work fine in this example. However, there are times when the
relative pointer control is the only way that you can move the pointer. Maybe you want to always have
exactly one space between values in your output. All you have to do is say +1 to move the pointer from
wherever it is over one space.
2. Creating Simple Listing Reports
27
Controlling the Line Pointer
Line pointer controls:
/
advances the pointer to column one of the
next line.
#n
moves the pointer to line n.
The value of n can be a numeric value, constant, or expression.
24
So far we have been controlling the pointer within one output line. Let’s talk about moving the pointer
between lines in the report.
The first time that SAS encounters a PUT statement, it, by default, starts writing on line 1. Every time that
SAS encounters a new PUT statement, it moves the pointer to a new line of output. What if you want to
start writing your report on line 5, instead of line 1, or what if you have a title on your report and now you
want to skip down two lines before writing the body of the report?
You can use the slash (/) line pointer control to advance the pointer to the next output line. If you have a
specific line number in mind, you can use the pound sign or hash (#) line pointer control. So, I could say
#5, and SAS will move the pointer, wherever it is, specifically to line 5.
Now, let's use those line pointer controls to place some lines on the output page in the LISTING
destination.
28
Creating DATA Step Reports with the LISTING Destination
Using Line Pointer and Column Pointer Controls
Line pointer controls advance the pointer between lines.
put @6 'Comparing Administration Department Job Salaries'
#2 @23 'In US Dollars'//
@3 'Country' @15 'Title' @48 'Salary' /;
Line #1
Line #2
Line #3
Line #4
25
Let’s use the slash and pound (#) sign line pointer controls to add a title to our report. For now, we’ll
assume that our report is only one page long. Later, we’ll see how to add titles to multiple pages of a
report.
Using this PUT statement:
• When SAS is writing to the output buffer, by default, it starts writing in line 1. Then in this example, it
is instructed to move the pointer to column 6.
• Then with the pound, or hash, 2 (#2) instruction, SAS moves the pointer to the second line in the output
buffer and writes In US Dollars starting in column 23.
• Then we want to skip a line between the title and column headers in the body of our report. We use a
slash (/) to do so. Now the pointer is resting in column 1 on line 3.
• We need SAS to move down to line 4, so we’ll use another slash. On line 4, the headers are written,
starting in column 3.
Now we have the title and column headers for our report.
And notice this last slash puts a blank line between the column headers and the body of the report.
2. Creating Simple Listing Reports
29
Using Line Pointer and Column Pointer Controls
Line pointer controls are needed to
build this multiline detail report.
Represents one
observation in the input
data set
26
Up to this point, we have learned the basic statements that are needed to create a simple listing report and
we have learned some ways to control pointer movement within the output destination.
Let’s put the techniques that we have learned so far to work to build this report in which one observation
spans multiple lines. Here we have a block of information on the report for each observation in the input
data set.
30
Creating DATA Step Reports with the LISTING Destination
Creating a Simple Listing Report
This demonstration shows the program that was used to
create the report on the previous slide.
27
I am going to demonstrate the program that was used to create the report on the last slide.
The report that we want to create will contain only employees from Australia who work in the
Administration department. We want the report sorted by employee name. Here is the complete program.
• I have added an OPTIONS statement at the top of the program to keep the date and page number from
displaying on the report. We are just keeping things simple for now. We’ll discuss the OPTIONS
statement in the next section.
• Then I have a PROC SORT step. The PROC SORT step sorts the original data set by employee names,
and writes the sorted version to a new temporary data set named work.employees. This way, the
original order of the data will not be disturbed. To save some processing time, we are going to place the
WHERE statement in the PROC SORT step. Then, when we later use this data set in the DATA step,
we are only reading in the observations that we want to process at that time.
• Now, we have our DATA step, and in our SET statement we are reading from the data set that we just
sorted.
• The FILE statement contains the PRINT option that directs SAS to write to the default LISTING
destination, which in our case is the OUTPUT window since we are in the SAS windowing
environment.
• In our PUT statement, we are directing SAS to print an employee’s name, then move to the next line
and print the employee’s job title, then move to the the next line and print the employee’s hire date. For
each employee in our report, there will be three lines of output. The two slashes at the end of the PUT
statement place blank lines between each grouping.
2. Creating Simple Listing Reports
31
Let’s go ahead and submit this program and see what we get. Scrolling to the top of the output, we don’t
see any titles or footnotes, or page numbers or dates. Again, we’re just keeping this report very simple.
And, for each of our employees, we see three lines of output, just as we expected.
32
Creating DATA Step Reports with the LISTING Destination
3.
Enhancing Reports
Creating DATA Step Reports with the LISTING Destination
1. Introduction to DATA Step Reporting
2. Creating Simple Listing Reports
3. Enhancing Reports
4. Creating Summary Reports
5. Creating Multicolumn Reports
28
In this section, we’ll look at some additional statements and options to further customize our reports.
3. Enhancing Reports
Objectives
„
Generate column headers, titles, and footnotes.
„
Produce grand totals and subtotals.
29
We will add
• column headers, titles, and footnotes
• subtotal and grand total information to our report.
33
34
Creating DATA Step Reports with the LISTING Destination
Controlling Report Titles and Column Headers
General form of the HEADER= option in the FILE statement:
FILE PRINT NOTITLES HEADER=label;
label
defines a branch point within the code that is
associated with a group of statements that execute
when the DATA step begins printing a new page.
30
For our reports, we want total control over the placement of column headers and values, and even titles
and footnotes. So, instead of using TITLE statements for our reports, we will use the HEADER= option
in a FILE statement along with a header routine. We will create our column headings this way as well.
And for our footnotes, we’ll use another technique that we’ll discuss later.
Here is the syntax of the FILE statement:
• Remember that the NOTITLES option suppresses all titles from displaying, that is, ones that you have
created during this session or the default SAS title.
• The HEADER= option has been added to identify a labeled routine that contains the instructions for
outputting titles, and/or column headers at the top of every new page. This will take care of any
multipage reports that you produce. You get to choose the label name for the HEADER= option. The
name must follow SAS naming conventions.
3. Enhancing Reports
35
Creating Headers and Footers
This demonstration shows the final report containing titles,
column headings, and footnotes.
31
Now I'm going to demonstrate the final output from the program that we will be creating over the next
several slides. I don’t want to go over the program in detail yet. For right now, I just want you to see the
output that we are aiming to produce.
Here you see the program that we are going to work toward in the next several slides. We have our FILE
statement that we saw in the last section. Here is our header routine which produces our title at the top of
the report and column headers. We haven’t seen it. And, we haven’t seen this LINESLEFT=LEFT
option, this block of code, and this FOOT routine – all of which are going to produce our footnotes at the
bottom of each of the pages of our report. We are not going to worry about those right now.
I’m just going to submit this program and take a look at what we get as output. And here is our first page.
If I scroll down, I can see the footnote at the end of that first page. And if I scroll down a little further, I
can see the second page of my report. I didn’t completely fill up that second page. And, I see the
footnote at the bottom of that page.
So this is the report that we will be working toward as we work through the next section.
36
Creating DATA Step Reports with the LISTING Destination
Adding Column Headers
The HEADER= option points to a header routine.
options ps=45;
data _null_;
set orion.employees;
where employee_country in('AU','IT','FR', 'US')
and department='Administration';
file print notitles header=hd;
put @5 employee_country $2. @15 job_title $25.
@40 salary dollar14.2;
return;
hd:
put @6 'Comparing Administration Department Job Salaries'
#2 @23 'In US Dollars'//
@3 'Country' @15 'Title' @48 'Salary' /;
return;
32 run;
Let’s look in detail at the program that produced the report that we just saw:
• When SAS is at the top of a new page, and it gets ready to execute the PUT statement, it automatically
branches to the HEADER routine that we named hd in this example. Notice that hd has a colon after it.
• Within the header routine, any number of lines can be displayed, and any executable SAS statement
can be used. Here we have created a title, and we created column headers for the
employee_country, job_title, and salary variables.
• After the HEADER routine executes, SAS executes the RETURN statement. Without this RETURN
statement, SAS would not know to go back to the PUT statement. The PUT statement writes a line of
data, and then this RETURN statement returns SAS to the top of the program. Without this RETURN
statement, SAS would execute the header routine again.
The next time through the program, when SAS encounters the first PUT statement, it checks to see if it is
at the top of a new page. It is not, so it does not branch to the header routine.
3. Enhancing Reports
Output with Column Headers
Report so far…
33
If we execute the program, this is what page 1 of the output resembles up to this point. We have a
customized title, customized report headers, and everything is working great.
What if we wanted to add a footnote to the bottom of the report?
37
38
Creating DATA Step Reports with the LISTING Destination
Creating Footnotes
The LINK statement is useful for creating page footers or footnotes
on reports.
General form of the LINK statement:
LINK label;
34
To add a footnote, we will need to enlist the help of the LINK statement. The LINK statement enables
you to create a labeled routine for footnotes similar to the header routine that we saw.
The LINK statement branches to the group of statements identified by the label. After a RETURN
statement executes, control returns to the statement after the LINK statement.
3. Enhancing Reports
39
Creating Footnotes
To place a footnote or footer in a report, you have to know how far from
the bottom of the page to print it.
General form of the FILE statement:
FILE file-specification LINESLEFT=variable;
35
We also need the LINESLEFT=variable option. The LINESLEFT=variable option defines a variable
whose value is the number of printable lines remaining on the current page. You supply the variable
name, any variable name that you like, but do not use the name of a variable in the input data set.
The LINESLEFT=variable option is useful for determining whether there are enough remaining lines on
the page in order to
• write another observation so that you can avoid splitting an observation across two pages and keep
related information together, and
• write footnotes or page footers on a report.
40
Creating DATA Step Reports with the LISTING Destination
Creating Footnotes
Use the _PAGE_ specification to control page breaks.
PUT _PAGE_ ;
SAS automatically begins a new page when a line exceeds
the current PAGESIZE= value.
36
Finally, we need a way to instruct SAS to do a page eject after the footnote is printed.
If the PAGESIZE= value has been exceeded, then SAS does an automatic page eject. If we need to take
control of when the page eject should take place, the _PAGE_ specification in the PUT statement is used.
It advances the pointer to the first line of a new page.
3. Enhancing Reports
41
Creating Footnotes
37
options ps=45;
data _null_;
set orion.employees;
where employee_country in('AU','IT','FR', 'US')
and department='Administration';
file print notitles header=hd linesleft=left;
if left < 5 then do;
link foot;
put _page_;
end;
put @5 employee_country $2. @15 job_title $25.
@40 salary dollar14.2;
return;
hd:
put @6 'Comparing Administration Department Job Salaries' //
@3 'Country' @15 'Title' @48 'Salary' /;
return;
foot:
put #45 @2 'Note: All salaries are in US Dollars‘;
return;
run;
Putting it all together, this is what our program will look like.
• I placed the LINESLEFT= option in the FILE statement and I created a variable named left that will
be populated by SAS with the number of lines remaining on the current page.
• I added a block of syntax after the FILE statement. I ask if left is less than 5. I am checking to see if
five lines remain at that moment in time.
• Then I want SAS to link to the footer routine, which I labeled foot. SAS will then link to the label; it
will write the footnote on line 45 starting in column 2. Note, that the label here for foot has a colon
after it, not a semicolon.
• SAS will execute the RETURN statement and return to the end of the LINK FOOT; statement.
• Then it executes the PUT _PAGE_ statement. The pointer is now moved to the first line of a new page.
• Processing then continues through the rest of the DATA step. It is important to include the last
RETURN statement in the FOOT routine. Without that RETURN, SAS would not know to return to the
LINK FOOT; statement. Instead, SAS would hit the bottom of the implicit DATA step loop, and
control would return to the top of the implicit loop where SAS would encounter the SET statement
again.
42
Creating DATA Step Reports with the LISTING Destination
Output with Footnotes
Footnotes now appear at the
bottom of the first page.
38
If we look at the output results, we see the footnotes at the bottom of the first page.
3. Enhancing Reports
43
Last Page - No Footnotes
No footnotes appear on the last
page.
39
There is no footnote on the bottom of the second page. We said that if there were less than five lines at the
bottom of a page, then SAS should print a footnote. On this page, there are not enough rows being printed
to fill the page and have only five lines remaining. Therefore, SAS never executes the condition that
triggers the link to the footnote routine to print the footnote.
What is happening is that SAS is hitting the end of file for orion.employees before it has filled up
the last page of output. What we need is something that says, "If this is the end of the file, then go and
print a footnote at the bottom of the last page."
44
Creating DATA Step Reports with the LISTING Destination
Creating Footnotes
The END= option detects the end of the data.
SET SAS-data-sets END=variable;
MERGE SAS-data-sets END=variable;
UPDATE SAS-data-sets END=variable;
INFILE 'external file' END=variable;
40
The END= option creates a variable that
• indicates when the last line is read from the input data source
• has a value of 0 until the last record or observation is read.
When the last record is read, the value of the END= variable becomes 1. The END= option is
placed in a SET, MERGE, or UPDATE statement if you are reading from a SAS data set, and it is
placed in an INFILE statement if your input data source is an external data file.
3. Enhancing Reports
45
Creating Footnotes on the Last Page
41
options ps=45;
data _null_;
set orion.employees end=endfile;
where employee_country in('AU','IT','FR', 'US')
and department='Administration';
file print notitles header=hd linesleft=left;
if left < 5 then do;
link foot;
put _page_;
end;
put @5 employee_country $2. @15 job_title $25.
@40 salary dollar14.2;
if endfile=1 then link foot;
return;
hd:
put @6 'Comparing Administration Department Job Salaries' //
@3 'Country' @15 'Title' @48 'Salary' /;
return;
foot:
put #45 @2 'Note: All salaries are in US Dollars';
return;
run;
In our program, we placed the END= option in our SET statement and defined a variable named
ENDFILE. Then to check for the end of file in our program, we placed our IF statement immediately
after SAS writes a line of data, in other words, after the PUT statement.
• If this is the last line of data, then SAS links to the footer routine and prints a footnote on this last page.
• The RETURN statement sends the pointer back to the top of the DATA step.
• When SAS executes the SET statement, SAS realizes that it has reached the end of the data and DATA
step execution ends.
46
Creating DATA Step Reports with the LISTING Destination
Last Page - With Footnotes
Here are the output results with
the footnote now on the last
page.
42
With the END= option in effect, footnotes now print on every page of the report.
3. Enhancing Reports
Enhancing the Report
Page numbers and the date
that the report was run have
been added to the report.
43
I have enhanced the report a little further here by adding page numbers and the date that the report was
run.
47
48
Creating DATA Step Reports with the LISTING Destination
Adding Page Numbers and the Run Date
This demonstration applies the techniques presented in this
section to enhance the report.
44
Let’s move to a demonstration that will apply the techniques used in this section to create the report
shown on the last slide with page numbers and the run date.
And here is my program.
• To place page numbers at the top of our report, we are going to need a mechanism for keeping track of
what page SAS is writing to when it goes to the top of a new page. We’ll do that with a SUM
statement. We’ll name our accumulating variable page. We will add the SUM statement to the header
routine, because SAS only branches to the header routine at the top of a new page, and that is where we
want our page number to be placed.
• To display the page number, we are going to add the first part of this PUT statement telling SAS to
write out the text Page, and then to move over one column and write the current value of the userdefined variable named page.
• To add the date to the report, we are going to create a variable named date as you see here. This
variable is created as a result of the TODAY() function, which extracts the current date value from your
system’s clock.
• To display the date value, we will add it to the PUT statement. After SAS writes the page number, we
will instruct it to move over to column 45 and write the value of date.
• Then we will instruct SAS to skip a few lines between the page number, the date information, and the
title of the report.
• Notice that I split the title into two lines and centered it on the report for aesthetic purposes.
3. Enhancing Reports
49
We’ll execute this program, and here are the results. We have, on the first line of the report, the page
number and the date that the report was created, and the two-line title that is centered. Here is page 2.
Now, another way that I could display today’s date in the report would be to use an automatic macro
variable defined by SAS. There are several of these automatic macro variables. For example, there are
• &SYSDATE, which contains the date that the current SAS session started
• &SYSTIME, which contains the time that the current SAS system started.
We want to use &SYSDATE in our program.
We have no need to create a new variable to hold the date value, so I’m going to delete this line from the
program: date=today(). In the PUT statement, I will replace the date variable with the macro
variable, like this. Notice that I also place the macro variable in double quotation marks. That is because
SAS resolves the macro variable and the value is returned in the form of text. Text in the PUT statement
is surrounded by quotation marks. Without going into a lesson on macro variables, there is rule that
double quotation marks, not single quotation marks, are required when you place a macro variable inside
of quotation marks. I am also going to delete the DDYYMM10. format because the macro variable
always writes the date in a particular form. If you have a different format in mind, then don’t use
&SYSDATE. Use the DATE function and PUT statement that we discussed in the first example.
It’s as simple as that. We’re good to go, so let’s execute this program.
On the first page, you see the page number; we didn’t do anything with that. And, you see the date value.
It’s in a little different form then we saw on the last report, because that is the form that the macro
variable returned the date value.
Before we leave this demo, let me point out another difference between the two methods that I showed
you for displaying the date value on your report, besides controlling the format of the date value. Another
difference is what date is being displayed. The TODAY function grabs the current date, while the
&SYSDATE variable uses the date that the current SAS session was initiated or invoked.
50
Creating DATA Step Reports with the LISTING Destination
Adding Grand Totals and Subtotals
Use the END= option and the
SUM statement to create
grand totals.
Use First. and Last. BY
variables to create subtotals.
45
Our next task is to create the report shown on this screen. We want to break down the report by country.
We want to know what the total salaries are for each country’s administrative staff, and we want a grand
total for everyone as well.
To create the grand total on the report, we will use the END= option that we used to generate the footnote
on the last page of the report. We need to use a SUM statement to accumulate the overall salary total that
represents the grand total.
To create the subtotals on the report, we will add a BY statement to the program so that the automatic
variables First.variable-name and Last.variable-name are created. Then we will use these special
automatic variables to accumulate the subtotals for each country.
3. Enhancing Reports
51
Adding Grand Totals
proc sort data=orion.employees out=work.employees;
by employee_country;
run;
options ps=45;
data _null_;
set work.employees end=endfile;
where employee_country in('AU','IT','FR', 'US')
and department='Administration';
file print notitles header=hd;
alltotsal+salary;
put @5 employee_country $2. @15 job_title $25.@40 salary dollar14.2;
if endfile=1 then
put // @5 'Total for all countries ' @38 alltotsal dollar16.2;
return;
hd:
put @6 'Comparing Administration Department Job Salaries' //
@3 'Country' @15 'Title' @48 'Salary' /;
return;
run;
46
First let’s tackle the grand total because we have already learned what we need to create it.
We are going to use the last program that we created as a starting point and modify it. We have already
covered the shaded parts of the program. The parts you see in black have been added to generate the
grand total.
In this new report, we do not want footnotes. Instead we want a grand total at the bottom of just the last
page. Therefore, I have removed the LINESLEFT= option, the block of code that checks the number of
lines left and links to the footer routine, and I have removed the footer routine from the program.
• I added the END= option to the SET statement, so we can later check for the end of file to print the
grand total.
• I added this SUM statement to accumulate the grand total into the alltotsal variable. Notice that it
is placed just after SAS reads in a new observation. So each time an observation is read in, the salary
value for that observation is added to the overall salary value.
• I also added this IF statement to check when SAS reaches the end of the input data. When it has, I want
it to skip a couple of lines and then write the text Total for all countries and the
alltotsal value. And…
52
Creating DATA Step Reports with the LISTING Destination
Output Results with Grand Totals
The grand total has been added.
47
As you can see, the grand total has now been added to the bottom of the report.
3. Enhancing Reports
53
Using BY-Group Processing to Produce Subtotals
The use of a BY statement in the DATA step enables you to process
your data in groups.
DATA _NULL_ ;
SET libref.filename;
BY BY-variable;
<additional statements>
RUN;
The data must be sorted or indexed by the BY variable(s).
48
We also want to add subtotals in the report for each employee country. To create subtotals, we are going
to use a BY statement in the DATA step. Remember that whenever you use a BY statement anywhere in
SAS, the data must first be sorted or indexed by the variables in the BY statement.
Just a little aside… Technically, the data doesn’t have to be sorted or indexed if you use the
NOTSORTED keyword in the BY statement. However, you may not get what you expect if the BY
groups are not contiguous in the file. So, sorting or indexing the data first will create the results that you
want.
54
Creating DATA Step Reports with the LISTING Destination
Using BY-Group Processing to Produce Subtotals
A BY statement in the DATA step creates temporary variables for each
variable listed in the BY statement.
For example:
first.employee_country;
BY employee_country;
last.employee_country;
BY employee_country
job_title;
49
first.employee_country,
first.job_title
last.employee_country,
last.job_title
When you use a BY statement in a DATA step, two special SAS variables are automatically created for
each variable that you have listed in the BY statement. They are First.BY-variable and Last.BYvariable.
In this first example, a first.employee_country variable is created and a
last.employee_country variable is created.
In the second example, two First.BY-variables are created. There will be a
first.employee_country and a first.job_title. The same is true of Last.BY-variable.
We will get a last.employee_country and a last.job_title.
Remember that the data must be sorted or indexed by all of the variables listed in the BY statement.
3. Enhancing Reports
55
Adding Subtotals
proc sort data=orion.employees out=work.employees;
by employee_country;
run;
50
options ps=45;
data _null_;
set work.employees end=endfile;
by employee_country;
<additional statements>
if first.employee_country then totsal=0;
totsal+salary;
alltotsal+salary;
put @5 employee_country $2. @15 job_title $25. @40 salary dollar14.2;
if last.employee_country then put @38 '________________' /
@5 'Total for ' employee_country @38 totsal dollar16.2 /;
if endfile=1 then
put // @5 'Total for all countries ' @38 alltotsal dollar16.2;
return;
hd:
put @6 'Comparing Administration Department Job Salaries' //
@3 'Country' @15 'Title' @48 'Salary' /;
return;
run;
Again, we’ll start with the last program that we wrote and modify it by adding the parts that you see in
black.
• To subtotal the report by employee countries, we want to make use of the First. and Last.BYvariables in the DATA step. To do that, we’ll add a BY statement in the DATA step to create these
variables. Remember that the BY statement in the DATA step requires that the data be sorted by
employee_country. We have a PROC SORT step here that satisfies that sort requirement.
• Next we’ll add the IF statement. If this is the first.employee_country (for example, if this is
the first AU), then we want to start a running total for that country. That total should start at zero. When
the subtotaling starts for the next country, we want it to start at zero again. So, this statement always
starts the subtotaling for a country back to zero for the first encounter of that country.
• Then we want to calculate the salary subtotal for each country with this SUM statement. For each
AU observation, for example, the salary for that observation will be accumulated into the variable
totsal.
• We then want to display the subtotal information at the end of each employee country grouping. So,
this IF statement has been added. After the last observation in a grouping has been written, we want
SAS move to a new output line and write the text Total for, then write the value of
employee_country, and then the subtotal for that country in column 38. And now we have…
56
Creating DATA Step Reports with the LISTING Destination
Output Results with Subtotals
The report now has subtotals and
a grand total.
51
…the final report. In this example, you see the subtotals for Italy and for the U.S., and then the grand total
for all countries.
4. Creating Summary Reports
4.
Creating Summary Reports
Creating DATA Step Reports with the LISTING Destination
1. Introduction to DATA Step Reporting
2. Creating Simple Listing Reports
3. Enhancing Reports
4. Creating Summary Reports
5. Creating Multicolumn Reports
52
Let’s move on and discuss how to create summary reports with the DATA step.
57
58
Creating DATA Step Reports with the LISTING Destination
Objectives
„
Use procedure output to generate summary reports.
53
To create summary reports, you can do either of the following:
• use procedures to generate the statistics and output those statistics to a SAS data set. Then we would
use the data set as input to create a DATA step report.
• generate the statistics in the DATA step and output them to a report all within the same DATA step.
This will save resources, because instead of processing two DATA steps, SAS will only be processing
one.
Typically, unless the statistics that you are displaying are very simple, you will get a procedure to do the
calculations for you.
4. Creating Summary Reports
Procedure Output as Input
Place the overall
statistics at the top of
the report.
54
In this report, we have overall statistics listed at the top of the report. Then summary statistics are also
displayed for each of the four countries in the report, as you see here.
59
60
Creating DATA Step Reports with the LISTING Destination
Producing Overall Report Statistics
proc means data=orion.employees;
var salary;
class employee_country;
where employee_country in('IT','AU','FR', 'US')
and department='Administration';
output out=work.means_stats n=count mean=avgsal sum=totsal
min=minsal max=maxsal;
run;
proc print data=work.means_stats;
run;
PROC PRINT Output of work.mean_stats
55
To create this report, we will first use PROC MEANS to generate the statistics that we need:
• The VAR statement tells SAS to analyze the salary variable.
• The CLASS statement says break down the statistics by countries.
• The WHERE statement subsets the data being read to produce the statistics.
• The OUTPUT OUT= statement is what sends N, MEAN, SUM, MIN, and MAX statistics into a SAS
data set named work.means_stats.
We’ll use PROC PRINT to view the contents of the output data set. Notice that there is a variable named
_type_ in this output data set. This is a variable that PROC MEANS automatically creates. Remember
that in the PROC MEANS step, we asked SAS to generate statistics for each country. The _type_
variable defines how the statistics are classified.
In the output data set:
• If _type_ has a value of 0, that means that the 57 that you see for the count variable and the
$30,031 for the avgsal variable are overall statistics. We are not dividing the report by any countries.
• When _type_ has a value of 1, the statistics that you see are separated by employee_country
values. We specified four countries in the WHERE statement, so there are four observations in this data
set, where _type_=1. In the second observation, where _type_=1, the 13 that you see for the
count variable and the $29,300 for avgsal are statistics for employees in Australia only.
Now, we will use this output data set as input to a DATA step to layout and create the desired report.
4. Creating Summary Reports
61
Creating a Custom Format
This format takes the country codes and expands them
to the country names.
proc format;
value $country 'AU'='Australia'
'FR'='France'
'IT'='Italy'
'US'='United States'
Other='Not Formatted';
run;
56
Next, we will define the format for employee_country so that the actual country names print on the
report instead of the abbreviated two-letter country codes. Here is the format. We want the AU values to
be displayed as Australia and FR to print as France, and so on.
62
Creating DATA Step Reports with the LISTING Destination
Producing Overall Report Statistics
57
data _null_;
set work.means_stats end=endfile;
file print notitles header=hd;
if _type_ ne 0 then put employee_country $country.//
@5 'Sum of salaries:'
@25 totsal dollar14.2
@45 'Average salary:'
@60 avgsal dollar14.2 /
@5 'Maximum salary:'
@25 maxsal dollar14.2
@45 'Minimum salary:'
@60 minsal dollar14.2 /
@5 'Number of employees:' @25 count 14. /
80*'=';
else put @5 'Overall Salary Totals:'
@30 totsal dollar14.2 //
@5 'Overall Average Salary:'
@30 avgsal dollar14.2 //
@5 'Overall Minimum Salary:'
@30 minsal dollar14.2 //
@5 'Overall Maximum Salary:'
@30 maxsal dollar14.2 //
@5 'Total Number of Employees:' @30 count 14. //80*'-';
if endfile=1 then link foot;
return;
hd:
put @25 'Administration Salary Statistics' ////;
return;
foot:
put #45 'Note: All salaries are in US dollars';
return;
run;
Let’s take a look at the DATA step program:
• The first time through the DATA step, SAS reads observation 1, which contains a _type_ value of 0.
• SAS checks the if _type_ ne 0 condition. The condition is false, so it skips down to the ELSE
PUT statement. It might seem more logical to check for a _type_ of 0 first, but for efficient
programming, you should always place your IF conditions in the order of frequency that they will be
satisfied.
• SAS executes the PUT statement and branches to the header routine and prints the title of the report.
• SAS executes the RETURN statement and branches back to the PUT statement where it writes the
overall statistics from observation 1 to the output buffer.
• SAS checks to see if it is at end of file. It is not.
• SAS encounters the RETURN statement, which sends it to the top of the DATA step loop.
• The second time through, SAS reads observation 2.
• It checks the if _type_ ne 0 condition. The condition is true this time, so SAS prints information
for Australia.
• Processing continues until all of the country information is output.
• Then SAS sees that it is at the end of the file and prints the footnote.
4. Creating Summary Reports
Output Results
Now the statistics are at
the top of the report.
58
After we execute the program, here is the report. Try to create this report in a procedure. It would be a
stretch!
63
64
Creating DATA Step Reports with the LISTING Destination
5.
Creating Multicolumn Reports
Creating DATA Step Reports with the LISTING Destination
1. Introduction to DATA Step Reporting
2. Creating Simple Listing Reports
3. Enhancing Reports
4. Creating Summary Reports
5. Creating Multicolumn Reports
59
Let’s move on and discuss how to create multicolumn reports with the DATA step.
5. Creating Multicolumn Reports
Objectives
„
Explain and use the trailing @ specification.
„
Explain and use the N= option.
„
Generate a left-to-right multicolumn report.
60
We will need to learn a few new techniques to create these types of reports. We will learn how to use
• the trailing @ that holds the pointer on a line of output
• the N= option to control the number of lines available in the output buffer.
65
66
Creating DATA Step Reports with the LISTING Destination
Producing Multicolumn Reports
①
③
②
➃
61
Here is the multicolumn report that we will be producing.
Again, the basic assumption is that we need to produce this report in the LISTING destination with a
DATA step program. So, we want SAS to display observation 1 from the input data set, and then move to
the right and place observation 2 in a second column. Then for the third observation, we want SAS to
move to the next line and display observation 3 in the left column. Next, we want SAS to display
observation 4 in the right column. So, this will be a two-panel or two-column report where the values
cross from the left to the right panel as observations are output.
5. Creating Multicolumn Reports
67
Displaying Multiple Observations on the Same Line
You can use the trailing @ sign in the PUT statement to
„
hold the current line for the next PUT statement
„
eliminate repetitive occurrences of a value.
General form of the PUT statement with the trailing @ sign:
PUT specification(s) . . . @;
62
To be able to write multiple observations on one line of output, we will need to use the trailing @, which
is placed in an INPUT or PUT statement depending on how you are using it. We will be using it in the
PUT statement.
Normally, when SAS encounters a PUT statement, it advances the pointer to the next output row, and
then writes what it is directed by the PUT statement. At the end of the PUT statement, the pointer waits
for the next set of instructions. Maybe that is another PUT statement, which will advance the pointer to
the next output row, or maybe a line pointer control that explicitly tells SAS to move to the next row of
output.
If you place a trailing @ at the end of a PUT statement, that indicates that if you encounter another PUT
statement, do not move to the next row in the output destination. Keep writing to the current row. This
enables SAS to write part of a row of information, stop, and do something such as check some values, and
then continue writing on the same row with a second PUT statement. This also enables you to generate a
multicolumn report, as we will be doing.
Looking at an example is always easier.
68
Creating DATA Step Reports with the LISTING Destination
Using the N= Option
The N= option
„
is placed in the FILE statement
„
creates a multiline output buffer with dimensions defined
by the LS and PS system options
„
enables you to address any location on the output page by using
the # and @ pointer controls in the PUT statement.
63
To be able to process and print multiple observations in multiple iterations of the DATA step and go back
to the top of the report and print a summary statistic (in our case, the count or total number of employees),
we need to use the N= option. This option, which is placed in the FILE statement, is frequently used when
writing DATA step reports.
For all of the reports that we created to this point, when SAS executes a PUT statement, it writes to an
output buffer that is one line long. After SAS writes a line to the output buffer, it cannot go backwards,
only forwards. For example, after line 1 has been written in the output buffer and the pointer moves down
to line 2, SAS cannot go back up to line 1 again unless it is working in a multiline output buffer.
The N= option in the FILE statement enables you to specify the number of lines that are available to the
output pointer in the current iteration of the DATA step. You can say N=20. Then you will have a 20-line
output buffer available to move the pointer around. We want control over one page of the report at a time,
so we will use N=PS. PS relates to the PAGESIZE= option. Whatever it is set to is what the N= value will
become.
5. Creating Multicolumn Reports
69
proc sort data=orion.employees out=work.employees;
by employee_country department employee_name;
run;
options ps=50;
data _null_;
set work.employees end=endfile;
by employee_country department;
where employee_country in('AU','FR')and
department in('Administration','Engineering');
file print notitles header=hd n=ps column=currcol;
if last.employee_country ne 1 and first.department=1 then
put #8 @1 'Country: ' employee_country $country.
@30 'Department: ' department / @1 60*'-'/@;
count+1;
if currcol < 30 then put @1 employee_name $30.@;
else put @40 employee_name $30.;
if last.department = 1 then do;
put #5 'Total Number of Employees: ' count;
if endfile ne 1 then put _page_;
count=0;
end;
return;
hd:
put @12 'Worldwide Employees by Country and Department' ;
return;
64
run;
Let’s investigate the program for the report, looking at it in pieces. The shaded portion will be discussed
on the next slide. Starting at the top of the program:
• We will sort the data set by the employee countries first, then within that, by their departments. That
way, we’ll see our groupings in alphabetic order. Then within the groupings, when the individual
employee names are displayed, it would be nice to see them in alphabetic order as well. So, we’ll also
sort the data by employee_name.
• We are going to set a page size of 50 in this OPTIONS statement.
• Notice that the SET statement contains the END= option. We’ll talk about how we use that later.
• The BY statement contains the variables employee_country and department. Remember that
we sorted the input data set by employee_country and department and employee_name.
So, we satisfied the sort criteria for the BY statement.
• The FILE statement contains two new items: N=PS and COLUMN=CURRCOL. We discussed that
N=PS will create an output buffer that is an entire page in size. We need to control the whole page,
because SAS will be printing one observation in a grouping at a time and accumulating the count one
observation at a time for the entire grouping. When SAS reaches the end of a grouping, we will direct
the pointer in the output buffer to move back up above the grouping and print the total count. So, again,
we need the ability to move the pointer around the output buffer as needed. The COLUMN= option
keeps track of where the pointer currently resides in the output buffer. We’ll see the need for this later.
70
Creating DATA Step Reports with the LISTING Destination
if last.employee_country ne 1 and first.department=1 then
put #8 @1 'Country: ' employee_country $country.
@30 'Department: ' department / @1 60*'-'/@;
count+1;
if currcol < 30 then put @1 employee_name $30.@;
else put @40 employee_name $30.;
if last.department = 1 then do;
put #5 'Total Number of Employees: ' count;
if endfile ne 1 then put _page_;
count=0;
end;
return;
hd:
put @12 'Worldwide Employees by Country and Department' ;
return;
run;
65
Let’s continue further down in the program. I have also included a snapshot of a piece of our report so
that we can see how it is being built as we move through the program.
• If SAS comes across the first department value of a group, then it should move down to line 8 and
write the employee_country and department values and then a dashed line. At this point, the
current observation is the first department value, so the condition is true and SAS executes the PUT
statement. It checks to see if it is at the top of a new page. It is, so it branches down to the header
routine and prints out the title. The pointer in the output buffer is now resting at the end of the title.
Then it prints the country information and department values for the grouping and the dashed line.
Notice that the values of country are formatted. We are in the same SAS session that created the
$COUNTRY. format earlier, so you don’t see the code for that here. Also, notice that the count
information has not been written yet.
• Now we want SAS to print the current employee_name value starting in column 1 of the next line.
But, thinking ahead, on the following iteration of the DATA step, we don’t want SAS to put that
observation in column 1. We want it to move over to column 40, to the right-hand column. So, what we
need to do is to set up two conditions. We need to tell SAS to print one observation in column 1, then
the next in 40, then start over in column 1, and then next in column 40, alternating back and forth. Here
is the IF logic.
• Next, we want SAS to count the number of employees in each group, so we’ll use a SUM statement for
that. Each time, SAS cycles up to the top of the DATA step and reads in a new observation. When it
encounters this statement, it will increment count by 1. We are not displaying the count yet, only
accumulating it.
5. Creating Multicolumn Reports
71
• After SAS prints the employee name for the current observation, the pointer will be resting past column
30. So, on the next iteration of the DATA step, we want the observation to print on the same row, but
in the right column. If the pointer rests in the left column, that means that the observation needs to be
written on the left side of the report. If the pointer has passed column 30, that means that the next
observation needs to be written in the right column. Remember that we defined currcol in the FILE
statement and it keeps track of where the pointer currently resides in the output buffer.
• SAS checks to see if the current observation is the last in a grouping. If so, it goes up to line 5 on the
current page, above the employee name columns and prints the total number of employees. If it is not at
the end of file, it does a page eject. That way each grouping is on a separate page. For the last grouping,
we don’t want SAS to do a page eject, because if it did, it would be at the top of a new page and print a
title. So, the last page of the report would only contain a title.
• It resets count to 0 after each grouping prints. Otherwise, count would represent the overall count.
72
Creating DATA Step Reports with the LISTING Destination
Creating a Multicolumn Report
66
Here are three of the four pages of the report. Remember that we asked for each country/department
combination to be placed on different pages. This report could not be created anywhere in SAS except in
the DATA step writing to the LISTING destination.
5. Creating Multicolumn Reports
73
Summary
A typical DATA step program for generating a report contains the
following components and can contain various options as well.
67
DATA
_NULL_
SET and
INFILE/INPUT
END=
FILE
PRINT
NOTITLES
HEADER=
LINESLEFT=
N=
PUT
Column and line pointer controls
_PAGE_
Trailing @
Alignment specifications (-L, -C, -R)
This concludes our discussion of building reports with the DATA step and sending them to the LISTING
destination.
Before I exit, I would like to quickly summarize what we have discussed in this e-lecture. We learned that
there are four components that you typically find in DATA step reports. They are …
• The DATA statement that tells SAS where to write the results of the DATA step. If want to create a
report, then you use the _NULL_ option in the DATA statement to prevent a data set from being
created.
• Then you would have a SET statement or an INFILE and INPUT statement combination to specify
your input data source for your report. You might need to use the END= option to give SAS a special
instruction when it reaches the end of the file in the input data source.
• You would have a FILE statement to direct the output results to a destination. If you want to write to
the default SAS LISTING destination, then you would use the PRINT option in the FILE statement.
There are other options that we used in the FILE statement as well. NOTITLES suppresses titles from
printing because we want to take control over the placement of the titles on the report. There is the
HEADER= option to direct SAS to perform a page eject after filling a page of output. The
LINESLEFT= option keeps track of how many lines remain at the bottom of an output page. The N=
option gives you control over the entire output buffer at one time, instead of one line at a time.
• Then you have a PUT statement to write information to the output buffer. You can use column pointer
controls and line pointer controls to position the information where you want it in the output buffer.
You can use the _PAGE_ option to force page breaks. The trailing @ is very useful when you need to
74
Creating DATA Step Reports with the LISTING Destination
write information to one line of output using more than one PUT statement. You can justify the data
values within columns of the report with the –L, –C, and –R specifications in the FILE statement.
5. Creating Multicolumn Reports
75
Summary
Other statements and techniques can be used to generate
DATA step reports:
Statements
OPTIONS
Options
LS=
PS=
RETURN
LINK
BY
First. and Last. BY variables
SUM
68
We also looked at automatic macro variables: &SYSDATE and &SYSTIME.
We saw other statements as well.
• The OPTIONS statement enables us to change SAS system options. We used the OPTIONS statement
to specify the line size (or width) and page size (length) of our reports.
• We used the RETURN statement in conjunction with the LINK statement and the HEADER= option.
This statement directs SAS to stop executing statements at the current point in the DATA step and
return to a predetermined point.
• The LINK statement was used to branch to a labeled routine in the DATA step. We used this to create
footnotes in the reports.
• The BY statement, when used in the DATA step, created two special variables: First.BY-variable
and Last.BY-variable. We used these two variables when we were grouping the report to create
subtotals.
• The SUM statement was used to accumulate subtotal and grand total values.
We also took a quick look at automatic macro variables such as &SYSDATE and &SYSTIME.
As you can see, we covered a lot of ground in this e-lecture. Remember that you are generating reports
with the DATA step, so any DATA step statements are available to you. We didn’t see examples with
ARRAY statements or DO LOOPS, but these are commonly seen in DATA step reporting.
76
Creating DATA Step Reports with the LISTING Destination
Other Related e-Lectures
These e-lectures might also be of interest:
Creating DATA Step Reports with the Output Delivery System
Customizing Output from the TABULATE Procedure with ODS
Customizing Output from the REPORT Procedure with ODS
A complete list of available SAS training, including SAS e-Lectures,
can be found at the following site:
http://support.sas.com/training
69
Remember that this e-lecture has highlighted syntax specific to the LISTING destination and DATA
_NULL_. Some options, such as the NOTITLE option, will work with ODS HTML, RTF, and PDF
destinations. However, other syntax examples, such as PUT @15 and PUT @32, will not work the same
way in other ODS destinations as they do in the LISTING destination. What you might find is that you
have legacy programs, perhaps run in batch or on the mainframe, that use these techniques. If you have to
change the programs or if you need to generate new, free-format reports, then you will need to master the
techniques shown in this e-lecture.
However, if you are doing new development of tabular reports, you might want to investigate the use of
ODS and DATA _NULL_ specific syntax to accomplish that task. See the companion SAS e-Lecture
Creating DATA Step Reports with the Output Delivery System for more on this capability. You might also
be interested in other ODS lectures such as Customizing Output from the TABULATE Procedure with
ODS and Customizing Output from the REPORT Procedure with ODS. Please visit the SAS Web site at
http://support.sas.com/training/ for a complete list of available e-lectures and other SAS training.
5. Creating Multicolumn Reports
Credits
Creating DATA Step Reports with the LISTING Destination was
developed by Linda Mitterling. Additional contributions were made
by David Ghan, Chevell Parker, Lorilyn Russell, Jason Secosky,
and Cynthia Zender.
70
Many thanks go to all of those who contributed to the creation of this e-lecture. We hope that you found
the material and presentation helpful.
77
78
Creating DATA Step Reports with the LISTING Destination
Comments?
We would like to hear what you think.
„
Do you have any comments about this lecture?
„
Did you find the information in this lecture useful?
„
What other e-lectures would you like to see SAS develop
in the future?
Please e-mail your comments to
[email protected]
71
SAS Education would like to know what you think about this e-lecture and e-lectures in general, If you
have any comments, we would greatly appreciate receiving your input. You can use the e-mail address
listed here to provide that feedback, or fill out the short evaluation at the end of this lecture.
5. Creating Multicolumn Reports
Copyright
SAS and all other SAS Institute Inc. product or service names are
registered trademarks or trademarks of SAS Institute Inc. in the USA
and other countries.
® indicates USA registration. Other brand and product names
are trademarks of their respective companies.
Copyright © 2008 by SAS Institute Inc., Cary, NC 27513, USA.
All rights reserved.
72
Thank you.
79
80
Creating DATA Step Reports with the LISTING Destination
Appendix A Lecture and
Demonstration Code
1.
Creating a Simple Listing Report ................................................................................. A-3
2.
Creating Headers and Footers ..................................................................................... A-4
3.
Adding Page Numbers and Run Date .......................................................................... A-5
A-2
Appendix A Lecture and Demonstration Code
1. Creating a Simple Listing Report
1.
Creating a Simple Listing Report
Section 2, slide 27
options nodate nonumber;
proc sort data=orion.employees out=work.employees;
by employee_name;
where department='Administration' and employee_country='AU';
run;
data _null_;
set work.employees;
file print;
put @10 'Name: ' employee_name /
@10 'Title: ' job_title /
@10 'Hire Date: ' employee_hire_date date9.
run;
//;
A-3
A-4
Appendix A Lecture and Demonstration Code
2.
Creating Headers and Footers
Section 3 slide 31
options ps=45;
data _null_;
set orion.employees end=endfile;
where employee_country in('AU','IT','FR', 'US')
and department='Administration';
file print notitles header=hd linesleft=left;
if left < 5 then do;
link foot;
put _page_;
end;
put @5 employee_country $2. @15 job_title $25.
@40 salary dollar14.2;
if endfile=1 then link foot;
return;
hd:
put @6 'Comparing Administration Department Job Salaries'//
@3 'Country' @15 'Title' @48 'Salary' /;
return;
foot:
put #45 @2 'Note: All salaries are in US Dollars';
return;
run;
3. Adding Page Numbers and Run Date
3.
Adding Page Numbers and Run Date
Section 3 slide 44
options ps=45;
data _null_;
set orion.employees end=endfile;
where employee_country in('AU','IT','FR', 'US')
and department='Administration';
file print notitles header=hd linesleft=left;
if left < 5 then do;
link foot;
put _page_;
end;
put @5 employee_country $2. @15 job_title $25.
@40 salary dollar14.2;
if endfile=1 then link foot;
return;
hd:
date=today();
page+1;
put 'Page' +1 page 2. @45 date ddmmyy10. ///
put @15 'Comparing Administration Department'/
@27 'Job Salaries' //
@3 'Country' @15 'Title' @48 'Salary' /;
return;
foot:
put #45 @2 'Note: All salaries are in US Dollars';
return;
run;
options ps=45;
data _null_;
set orion.employees end=endfile;
where employee_country in('AU','IT','FR', 'US')
and department='Administration';
file print notitles header=hd linesleft=left;
if left < 5 then do;
link foot;
put _page_;
end;
put @5 employee_country $2. @15 job_title $25.
@40 salary dollar14.2;
if endfile=1 then link foot;
return;
hd:
page+1;
put 'Page' +1 page 2. @45 "&sysdate9." ///
put @15 'Comparing Administration Department'/
@27 'Job Salaries' //
A-5
A-6
Appendix A Lecture and Demonstration Code
@3 'Country' @15 'Title' @48 'Salary' /;
return;
foot:
put #45 @2 'Note: All salaries are in US Dollars';
return;
run;