There are two common problems among beginning Cobol programmers concerning
summaries. The first problem is where do I get the totals? Secondly, where should I print
the summaries and why do I seem to get the summaries on a page by themselves with column
heading? We'll first look at accumulating totals and then printing the summary
information.
Accumulating Summary Totals
Before you can print the totals you MUST accumulate them. Remember that the real logic
of your program is in the procedure division. Also, when we process a record we are
performing an iteration. That simply means we go through a certain series of steps for
ever record we process. If our detail line contains the prices of certain items and we
want to ACCUMULATE the price of all of these items then we need an accumulator or
"bucket".Under a group name in the working storage section which you may call
NUMERIC-TOTALS you add an accumulator as follows: 01
NUMERIC-TOTALS.
03 LINES-PRINTED-SO-FAR PIC X(02).
03 RECORD-COUNT PIC X(03).
03 PAGE-COUNT PIC X(02).
03 SALES-TOTALS PIC 9(05)V99.
03 TOTAL-ITEMS PIC 9(03).
Notice I simply added and accumulator called Sales-Totals with an appropriate PIC
statement.I also want to accumulate the total items for each detail line. For instance I
sold 4 hats on one detail line and on the next line I sold 10c oats. When I process a
record (between my PERFORM-UNTIL and my END-PERFORM I need to add a line to do the accumulation.
The code in the procedure division (showing only important elements) might be as follows:
PERFORM kkl UNTIL EOF-FLAG = "YES"
ADD 1 TO RECORD-COUNT
MOVE NAME-IN TO NAME-OUT
MOVE ITEM-COUNT-IN TO ITEM-COUNT-OUT
ADD ITEM-COUNT TO TOTAL-ITEMS
END-PERFORM
Notice a line was added that sent the number of items that appears on each detail line
to an accumulator. Below is how our detail line might appear and what the accumulator
would contain.
ITEM
QTY
HATS 4
COATS 10
After processing these two records our accumulator called TOTAL-ITEMS
would hold 14. We added the ITEM-COUNT in each processed record to the
TOTAL-ITEMS accumulator. In a similar manner you can accumulate item counts, sales
amounts, department totals, etc.
An important note about RECORD-COUNT
Record count represents the total number of records processed. Every detail line you
print might represent some sales item or perhaps a student or employee record. It follows
logically that a RECORD-COUNT of 2 means I processed two item, students, employees,
etc. If on an advanced assignment you find you must check for good and bad records then
the following formula applies: Total records processed = number of good records processed
+ number of bad records processed. You can see you would have to set up an accumulator to
hold the number of bad records (that failed some test). You could then get the good
records by saying Total records processed - bad records.
To sum up accumulation you simply need to add the name of your accumulator as an
elementary item NUMERIC-TOTALS and then use and ADD statement WITHIN
the iteration where you are processing your record.
Printing the Summary Information
You can be as simply or fancy as you like in printing summary information.Remember that
your summary is handled AFTER you finish processing your records. At that point all the
information you need to directly or by calculations produce your summary information
resides in NUMERIC-TOTALS in one of the elementary items you created. The fancy way is to
create another top of page just for the summary. If you have the time and desire feel free
to do that but if it is not required then it is only extra work for you. Before you can
print your summary lines you need to decide whether you want to print one long summary
line with all the information or several. Printing several lines is easier to debug so I
suggest this if you want to keep things simple. In the following code which appears in
working storage one summary line is set up to print. To set up another line why not just
cut and past these lines directly below and then make some modifications.
01 SUMMARY-LINE-1.
03 PIC X(10) VALUE SPACES.
03 PIC X(26)
VALUE
'TOTAL NUMBER OF ITEMS SOLD '.
03 PIC X(10) VALUE SPACES.
03 TOTAL-P PIC Z99.
01 SUMMARY-LINE-1.
03 PIC X(10) VALUE
SPACES.
03 PIC X(26)
VALUE 'TOTAL NUMBER OF ITEMS SOLD '.
03 PIC X(10) VALUE
SPACES.
03 TOTAL-ITEMS-SL PIC Z99.
Notice I have two blocks of code that are identical I have to change the 5 areas that
are underlined and italicized. First you should change the group name to something
descriptive such as SUMMARY-LINE-2 Second, you need a new name for the summary line and a
new pic representing the length of this name. Third, I need a new total field and a new
PIC statement that reflects the proper size, type (alpha or numeric), and editing of the
output value. A possible change to output total number of records processed might be as
follows:
01 SUMMARY-LINE-2.
03 PIC X(10) VALUE
SPACES.
03 PIC X(23)
VALUE 'TOTAL RECORDS PROCESSED '.
03 PIC X(10) VALUE
SPACES.
03 TOTAL-RECS-SL PIC 999.
You add the number of summary lines you want. If you summary information for every
detail column such as with a bank statement you will want to create one group name and lay
out your summary line on a spacing chart.This way you can make sure all column headings,
detail columns, and summary information lines up on the final report.
The Procedure division component of printing summary
lines
We've discussed the actual accumulator and the summary line description both in working
storage but how do you get the summary line to print with the accumulator totals? The
following paragraph will move the accumulator called TOTAL-RECS to TOTAL-REC-SL and print
the line. Because we will have a line after our iteration like PERFORM 300-PRINT-SUMMARIES
we will perform the statements in this paragraph only once.
300-PRINT-SUMMARIES.
MOVE TOTAL-ITEMS TO TOTAL-REC-SL
MOVE SUMMARY-LINE-1 TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING 3 LINES.
What if we want a second summary line to print with a different summary item? Then we
cut and paste and make several changes. First, cut and paste a copy of the first 3 lines
to just below the original lines as follows:
300-PRINT-SUMMARIES.
MOVE TOTAL-ITEMS TO TOTAL-ITEMS-SL
MOVE SUMMARY-LINE-1 TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING3 LINES.
MOVE TOTAL-ITEMS
TO TOTAL-ITEMS-SL
MOVE SUMMARY-LINE-1 TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING3 LINES.
We only have to change the item we are moving from the numeric totals area and the
destination of that item. The changed code would look as follows:
MOVE TOTAL-ITEMS TO TOTAL-ITEMS-SL
MOVE SUMMARY-LINE-1 TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING3 LINES.
MOVE RECORD-COUNT
TO TOTAL-RECS-SL
MOVE SUMMARY-LINE-1 TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING3 LINES.
We would print two summary lines with the first being total items and the second being
total records with 3 spaces in between the lines.
Detail Column heading are above Summary information
on a separate page
This is a common problem that has a short but tricky answer. Consider the following
code:
PERFORM UNTIL EOF-FLAG = "YES"
ADD 1 TO RECORD-COUNT
MOVE NAME-IN TO NAME-OUT
MOVE ITEM-COUNT-IN TO ITEM-COUNT-OUT
ADD ITEM-COUNT TO TOTAL-ITEMS
MOVE REPORT-LINE TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING 2 LINES
ADD 2 TO LINES-PRINTED-SO-FAR
IF LINES-PRINTED-SO-FAR IS
GREATER THAN 20
MOVE
LINE-OF-EQUALS TO PRINT-OUT
WRITE
PRINT-OUT AFTER ADVANCING 2 LINES
PERFORM
100-TOP-OF-PAGE-ROUTINE
END-IF
READ SALES-FILE
AT END MOVE 'YES' TO EOF-FLAG
END-READ
END-PERFORM
Notice that within our iteration (between the PERFORM UNTIL EOF-FLAG= "YES"
and the END-PERFORM we have read our next
record. The first read (also called a prime read which could be avoided with a special
statement in Cobol 85) occurs before the iteration begins and is not shown.Lets move
several lines of code and look at the change in our logic. Consider the following code:
PERFORM UNTIL EOF-FLAG = "YES"
ADD 1 TO RECORD-COUNT
MOVE NAME-IN TO NAME-OUT
MOVE ITEM-COUNT-IN TO ITEM-COUNT-OUT
ADD ITEM-COUNT TO TOTAL-ITEMS
MOVE REPORT-LINE TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING 2 LINES
ADD 2 TO LINES-PRINTED-SO-FAR
READ SALES-FILE
AT END MOVE 'YES' TO EOF-FLAG
END-READ
IF LINES-PRINTED-SO-FAR IS
GREATER THAN 20
MOVE
LINE-OF-EQUALS TO PRINT-OUT
WRITE
PRINT-OUT AFTER ADVANCING 2 LINES
PERFORM
100-TOP-OF-PAGE-ROUTINE
END-IF
END-PERFORM.
Three lines have been moved but our the outcome of our processing is unaffected. Read
the code and prove to yourself that we haven't changed our output. We read the next record
before we tested to see if we needed a new top of page but after we made all the moves and
accumulations for the previously read record. If you are satisfied no change has been made
in the outcome of our processing then consider what is now available to us. If we read the
record before we do the test for a new page we have the switch change available to help us
decide when we need that new top of page.
We know that line IF LINES-PRINTED-SO-FAR IS GREATER THAN 20 will always give us a new
top of page when we have printed 20 lines. The problem is we may not want a top of page if
there are no more detail lines or we are printing the summary. Even without the summary
you may find a top of page printing all by itself complete with column headings but no
detail lines. This is because we filled up one page but the logic was written in
such a way that we found out we were out of records after we had already printed the top
of page. We can use the end of file condition in a compound conditional to easily solve
our problem.
PERFORM UNTIL EOF-FLAG = "YES"
ADD 1 TO RECORD-COUNT
MOVE NAME-IN TO NAME-OUT
MOVE ITEM-COUNT-IN TO ITEM-COUNT-OUT
ADD ITEM-COUNT TO TOTAL-ITEMS
MOVE REPORT-LINE TO PRINT-OUT
WRITE PRINT-OUT AFTER ADVANCING 2 LINES
ADD 2 TO LINES-PRINTED-SO-FAR
READ SALES-FILE
AT END MOVE 'YES' TO EOF-FLAG
END-READ
IF
LINES-PRINTED-SO-FAR> 20 AND EOF-FLAG NOT EQUAL TO "YES"
MOVE
LINE-OF-EQUALS TO PRINT-OUT
WRITE
PRINT-OUT AFTER ADVANCING 2 LINES
PERFORM
100-TOP-OF-PAGE-ROUTINE
END-IF
END-PERFORM.
The above code solves our problem. We changed the location of the read to
make the switch available. Also we added a compound conditional whose second component is
only FALSE one time--when we have no more records to print. Thus the printing of a new top
of page is suppressed after we are out of records and the summary will print without any
heading at all.
HOME