SAS Tutorial: Coding PUTs Without Coding PUTs

Jim Plaxco, Advantis; Prepared for WISAS, June 13, 1996

When using SAS* to produce reports, sometimes the PROC PRINT procedure is not capable of generating the desired output. In those instances, it is usual to resort to the use of "PUT" statements within a DATA step to create the needed report. However, laying out the report and coding the byte positions for all the headings and variables is a tedious and time consuming task. Furthermore, it must be redone each time the user decides that variables need to be added, deleted, or moved.

A prime example of this is the production of multicolumn reports. Here, multicolumn means a report that has more than one observation per line. Using PROC PRINT limits the output to one observation per line. It frequently happens that a user desires a report with just a few variables. Using PROC PRINT in this situation leads to the result that perhaps only 10-30 percent of the bytes available in a report line are used. This is a terrible waste of paper and/or, if the report is being written to a PDS with a record format of RECFM=FB, a terrible waste of disk space.

I was determined to produce multicolumn reports in these situations. In addition to saving paper and disk space, more data could be seen "at a glance." However, I didn't want to have to code unique solutions every time one of these reports came along. To lighten my programming burden, I developed three macros to automate the process of producing multicolumn reports. Instead of coding PUTs, macro parameters are used to control the layout of the report. The first of these macros is named HDRIN, whose source code is in Listing 4. I created this macro so that I could lay out complex column headings in a dataset, rather than in code. I use this macro in combination with another, HDROUT (not included here), to produce column headings for many reports. The second macro is named MULTIC, whose source code is in Listing 5. It is this macro that produces a report based on the user supplied parameter values.

The approach that I used in creating these two macros was to first write a SAS program that would generate the type of report that I wanted. This was done for several different report layouts. Once I had working SAS code, I then identified the variable elements of each program. I then proceeded to produce a macro that would generate the same SAS code given those variable elements as input parameters.

An example of one possible report output is presented in Listing 6. This report was "sized" so that everything would fit on one page. The SAS code that I had to actually write to produce the report itself is in Listing 1. The SAS code that was generated by the macros to produce the report is contained in Listing 2. As is evident, there is a substantial difference in complexity between the two listings.

Take a look at Listing 1. The details of the DATA step that was used to build the example data file, DATA1, have been omitted for purposes of clarity. In Line 13 of the DATA step, the macro variable TOTOBS is created. This variable contains the number of observations in the dataset that is to be printed, in this case DATA1. This macro variable is required by the MULTIC macro. Lines 14-16 of the DATA step create three macro variables: PHEAD1, PHEAD2, PHEAD3. These macro variables are used by MULTIC to produce the page headings for the report. Note that MULTIC allows for up to five of these "header line" macro variables.

Following the DATA step, the HDRIN macro is invoked (Line 19). This macro reads in as a data set the predefined column headings. Three parameters are required by HDRIN: the first is the name of the dataset where the column headings are found; the second is the name of the SAS dataset to create, HDR in this case; the third and final parameter is the number of bytes per line to read. The source code for HDRIN is in Listing 4. The contents of the dataset being processed, "JPLAXCO.P.HDRS(WS9605)," are in Listing 3. The SAS code that is generated as a result of the macro invocation is contained in Listing 2a, Lines 30-35. Note that this macro creates the macro variables HDRIN_N for the number of lines used by the column heading and HLEN for the bytes/line. These variables are used by MULTIC for page control.

The MULTIC macro is invoked in Line 22 of Listing 1. The MULTIC-generated SAS code is found in Lines 4 - 64 of Listing 2b. Let's begin by looking at how the parameters are used. Looking at the MULTIC invocation on Lines 2-3 of Listing 2b, the first parameter is "DATA1." This is the name of the dataset that is to be processed. It is used by the SET statement in Line 25. Notice that the SET statement is within a DO loop. MULTIC works by reading the variables to be printed into an array, one array per variable, one element per observation. Remember the TOTOBS macro variable - it is used in Lines 16-23 to set the upper bound for the arrays that are generated. The second parameter passed to MULTIC is "RPTOUT" which is the name of the DD that the report is to be written to. It is used by the FILE statement in Line 5. The next parameter is the number "3" which is used to specify the number of columns to be printed. It is also used by MULTIC to determine the number of array elements to print per page (EPP variable) and elements to print per column (EPC variable). In the generated SAS code, it is used to build the "ICn" variables (Lines 9-11), one per column. These variables control how the data is split into multiple columns. The next parameter, "150," tells MULTIC the line size ( the number of bytes per print line). Following that is the parameter value "52," which specifies how many lines per page to print.

Following these first five setup parameters are the parameters that identify what variables to print and how they are to be printed. MULTIC's parameter list allows the user to enter up to seven variables and their associated information.

The first variable that will be printed is "KDIAM." The parameters that follow KDIAM are "8,5,2,5.2." The "8" specifies the type and size of the array variable that will be used to store the observations for KDIAM. The "5" specifies the number of bytes to be reserved for the printing of the variable. The "2" specifies the number of blank padding bytes to be reserved on each side of the variable. The "5.2" is the output format that is to be used for printing the data. Any valid SAS Format can be used here. Because this variable is not used in any MULTIC calculations, a NULL parameter may be substituted if you want SAS to choose the form of the output - just be sure that you have reserved enough space for the printing of the variable. This sequence of parameters is repeated for the other three variables that are to be printed: DAMRAD, YIELD, and ABOMB.

An examination of the MULTIC source code in Listing 5, along with the generated SAS code in Listing 2 should be sufficient to provide an understanding of how the macro works. The programmer should be aware of the fact that MULTIC creates array variables based on the names of the variables that are passed to it in the parameter list. If the length of these variable names when combined with the element number that is appended to it exceeds 8 bytes in length, SAS will abend. A simple solution for this is to create one character array variable names. This would require changing Lines 4-5, and 14 in Listing 5b. Consideration must also be given to the fact that MULTIC creates a number a variables in the DATA step that it generates. These variables are in Lines 6-23 of Listing 2b. If there are variables of the same name in the dataset that is being read, the results will be unpredictable and, most likely, catastrophic. Lastly, using arrays to hold the values of the variables to be printed means that this solution is best used for the printing of datasets that have less than several thousand observations. An alternative implementation of MULTIC would be to use the random access feature of SAS as supported on the SET statement via the POINT= parameter. Hopefully, you will find this code a useful illustration of the power of SAS macros.

Program Listing Reference:

* SAS is a registered trademark of SAS Institute, Inc., Cary, NC, USA

Return to the Mainframe section index.