Book Read Free

Michael Coughlan

Page 28

by Beginning COBOL for Programmers-Apress (2014) (pdf)


  01 DetailLine.

  02 PrnStateName PIC X(14).

  88 SuppressStateName VALUE SPACES.

  02 PrnBranchId PIC BBX(5).

  88 SuppressBranchId VALUE SPACES.

  02 PrnSalespersonId PIC BBBBX(6).

  02 PrnSalespersonTotal PIC BB$$,$$9.99.

  211

  Chapter 10 ■ proCessing sequential Files

  01 BranchTotalLine.

  02 FILLER PIC X(43)

  VALUE " Branch Total: ".

  02 PrnBranchTotal PIC $$$,$$9.99.

  01 StateTotalLine.

  02 FILLER PIC X(40)

  VALUE " State Total : ".

  02 PrnStateTotal PIC $$,$$$,$$9.99.

  01 FinalTotalLine.

  02 FILLER PIC X(39)

  VALUE " Final Total :".

  02 PrnFinalTotal PIC $$$,$$$,$$9.99.

  01 SalespersonTotal PIC 9(4)V99.

  01 BranchTotal PIC 9(6)V99.

  01 StateTotal PIC 9(7)V99.

  01 FinalTotal PIC 9(9)V99.

  01 PrevStateName PIC X(14).

  01 PrevBranchId PIC X(5).

  01 PrevSalespersonId PIC X(6).

  PROCEDURE DIVISION.

  Begin.

  OPEN INPUT SalesFile

  OPEN OUTPUT SalesReport

  WRITE PrintLine FROM ReportHeading AFTER ADVANCING 1 LINE

  WRITE PrintLine FROM SubjectHeading AFTER ADVANCING 1 LINE

  READ SalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ

  PERFORM UNTIL EndOfSalesFile

  MOVE StateName TO PrevStateName, PrnStateName

  MOVE ZEROS TO StateTotal

  PERFORM SumSalesForState

  UNTIL StateName NOT = PrevStateName

  OR EndOfSalesFile

  MOVE StateTotal TO PrnStateTotal

  WRITE PrintLine FROM StateTotalLine AFTER ADVANCING 1 LINE

  END-PERFORM

  MOVE FinalTotal TO PrnFinalTotal

  WRITE PrintLine FROM FinalTotalLine AFTER ADVANCING 1 LINE

  CLOSE SalesFile, SalesReport

  STOP RUN.

  212

  Chapter 10 ■ proCessing sequential Files

  SumSalesForState.

  WRITE PrintLine FROM SPACES AFTER ADVANCING 1 LINE

  MOVE BranchId TO PrevBranchId, PrnBranchId

  MOVE ZEROS TO BranchTotal

  PERFORM SumSalesForBranch

  UNTIL BranchId NOT = PrevBranchId

  OR StateName NOT = PrevStateName

  OR EndOfSalesFile

  MOVE BranchTotal TO PrnBranchTotal

  WRITE PrintLine FROM BranchTotalLine AFTER ADVANCING 1 LINE.

  SumSalesForBranch.

  MOVE SalespersonId TO PrevSalespersonId, PrnSalespersonId

  MOVE ZEROS TO SalespersonTotal

  PERFORM SumSalespersonSales

  UNTIL SalespersonId NOT = PrevSalespersonId

  OR BranchId NOT = PrevBranchId

  OR StateName NOT = PrevStateName

  OR EndOfSalesFile

  MOVE SalespersonTotal TO PrnSalespersonTotal

  WRITE PrintLine FROM DetailLine AFTER ADVANCING 1 LINE

  SET SuppressBranchId TO TRUE

  SET SuppressStateName TO TRUE.

  SumSalespersonSales.

  ADD ValueOfSale TO SalespersonTotal, BranchTotal, StateTotal, FinalTotal

  READ SalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ.

  Program Notes

  The program in Listing 10-1 is fairly straightforward, once you understand that its structure mirrors the structure of the data and the report. It is interesting to contrast this program with a similar program given on the web site The American Programmer2. That program uses the single loop and IF statement approach mentioned earlier. One

  objection to this approach is that the three control items are tested for every record in the file.

  I draw your attention to the way in which the StateName and BranchId are suppressed after their first

  occurrence in Listing 10-1. This is done to make the report look less cluttered. To implement the suppression, the condition-name technique that you have seen in a number of other example programs is used. I could have implemented the suppression using a statement such as MOVE SPACES TO PrnStateName, but it would not have been obvious why the data item was being filled with spaces. The purpose of the statement SET SuppressStateName TO

  TRUE is easier to understand.

  Test Data and Results

  Due to space constraints, Figure 10-3 shows only a portion of the test data file and the report produced from that data is shown.

  2The Three Level Subtotal (Control Break) COBOL Program, TheAmericanProgrammer.Com, http://theamericanprogrammer.com/

  programming/08-brklv3.shtml.

  213

  Chapter 10 ■ proCessing sequential Files

  Figure 10-3. Fragment of the report produced and part of the test data file

  An Atypical Control Break

  The program in Listing 10-1 is a typical control-break program, but control-break problems come in a variety of shapes and sizes. For instance, you have probably realized by now that Exercise 1 at the end of the last chapter is a control-break problem but not a typical one. I didn’t provide a solution at the time because I wanted you discover for yourself some of the difficulties with this kind of problem and how easy it is to get dragged into a convoluted solution.

  Before I present my solution, let’s look at the specification again.

  Specification

  The Genealogists Society of Ireland wishes to discover the most popular surname used in each of the 26 counties in the Irish Republic. In order to obtain this information, the society has acquired a file containing a subset of data from the most recent census.

  A program is required that will process the census file and produce a report that shows, for each county, the most popular surname and the number of times it occurs.

  214

  Chapter 10 ■ proCessing sequential Files

  The census file is a standard sequential file with fixed-length fields. Each record contains a census number, a surname, and a county name. The file has been sorted and is now ordered on ascending Surname in ascending CountyName. Each record in the file has the following description:

  Field

  Type

  Length Value

  CensusNumber

  9

  8

  00000001–99999999

  Surname

  X

  20

  -

  CountyName

  X

  9

  -

  The report should take the format shown in the following report template. The Count field is a count of the number of times the Surname occurs in the county. In the Count field, thousands should be separated using a comma, and the field should be zero-suppressed up to, but not including, the last digit:

  Popular Surname Report

  CountyName Surname Count

  Carlow XXXXXXXXXXXXXXXXXXXX XXX,XXX

  Cavan XXXXXXXXXXXXXXXXXXXX XXX,XXX

  Clare XXXXXXXXXXXXXXXXXXXX XXX,XXX

  :: :: :: :: :: :: :: :: :: :: ::

  Westmeath XXXXXXXXXXXXXXXXXXXX XXX,XXX

  Wicklow XXXXXXXXXXXXXXXXXXXX XXX,XXX

  Wexford XXXXXXXXXXXXXXXXXXXX XXX,XXX

  ************* end of report ***************

  Atypical Control-Break Program

  This is not a typical control-break program (see Listing 10-2). Instead of printing the total number of occurrences of the surname when there is a change of surname (as a classic control-break program would do), there is a check to see if this surname is the most popular. A line is printed only when the major control item (the county name) changes.

  When that happens, the county name and the most popular surname are printed. There is a trap here for the unwary: when the control break occurs, it is too late to move the county name to the print line, because
at this point the county name in the buffer is the next county. The solution is to move PrevCountyName to the print line or to, as is done in this program, prime the print line with the correct county name before entering the loop that processes all the surnames in that county.

  Listing 10-2. Two-Level Control-Break Program Showing the Most Popular Surnames in the Counties of Ireland IDENTIFICATION DIVISION.

  PROGRAM-ID. Listing10-2.

  AUTHOR. Michael Coughlan.

  * Control Break program to process the Census file and produce

  * a report that shows, for each county, the most popular surname

  * and the number of times it occurs.

  * The Records in the sequential Census file are ordered on

  * ascending Surname within ascending CountyName.

  * The report must be printed in ascending CountyName order

  215

  Chapter 10 ■ proCessing sequential Files

  ENVIRONMENT DIVISION.

  INPUT-OUTPUT SECTION.

  FILE-CONTROL.

  SELECT CensusFile ASSIGN TO "Listing10-2TestData.Dat"

  ORGANIZATION IS LINE SEQUENTIAL.

  SELECT SurnameReport ASSIGN TO "Listing10-2.RPT"

  ORGANIZATION IS LINE SEQUENTIAL.

  DATA DIVISION.

  FILE SECTION.

  FD CensusFile.

  01 CensusRec.

  88 EndOfCensusFile VALUE HIGH-VALUES.

  02 CensusNum PIC 9(8).

  02 Surname PIC X(20).

  02 CountyName PIC X(9).

  FD SurnameReport.

  01 PrintLine PIC X(45).

  WORKING-STORAGE SECTION.

  01 ReportHeading.

  02 FILLER PIC X(13) VALUE SPACES.

  02 FILLER PIC X(22)

  VALUE "Popular Surname Report".

  01 SubjectHeading.

  02 FILLER PIC X(42)

  VALUE "CountyName Surname Count".

  01 CountySurnameLine.

  02 PrnCountyName PIC X(9).

  02 FILLER PIC X(3) VALUE SPACES.

  02 PrnSurname PIC X(20).

  02 PrnCount PIC BBBZZZ,ZZ9.

  01 ReportFooter PIC X(43)

  VALUE "************* end of report ***************".

  01 PrevCountyName PIC X(9).

  01 PrevSurname PIC X(20).

  01 MostPopularSurname PIC X(20).

  01 MostPopularCount PIC 9(6).

  01 SurnameCount PIC 9(6).

  PROCEDURE DIVISION.

  Begin.

  OPEN INPUT CensusFile

  OPEN OUTPUT SurnameReport

  WRITE PrintLine FROM ReportHeading AFTER ADVANCING 1 LINE

  WRITE PrintLine FROM SubjectHeading AFTER ADVANCING 1 LINE

  216

  Chapter 10 ■ proCessing sequential Files

  READ CensusFile

  AT END SET EndOfCensusFile TO TRUE

  END-READ

  PERFORM UNTIL EndOfCensusFile

  MOVE CountyName TO PrevCountyName, PrnCountyName

  MOVE ZEROS TO MostPopularCount

  MOVE SPACES TO MostPopularSurname

  PERFORM FindMostPopularSurname

  UNTIL CountyName NOT EQUAL TO PrevCountyName

  OR EndOfCensusFile

  MOVE MostPopularCount TO PrnCount

  MOVE MostPopularSurname TO PrnSurname

  WRITE PrintLine FROM CountySurnameLine AFTER ADVANCING 1 LINE

  END-PERFORM

  WRITE PrintLine FROM ReportFooter AFTER ADVANCING 2 LINES

  CLOSE CensusFile, SurnameReport

  STOP RUN.

  FindMostPopularSurname.

  MOVE Surname TO PrevSurname

  PERFORM CountSurnameOccurs VARYING SurnameCount FROM 0 BY 1

  UNTIL Surname NOT EQUAL TO PrevSurname

  OR CountyName NOT EQUAL TO PrevCountyName

  OR EndOfCensusFile

  IF SurnameCount > MostPopularCount

  MOVE SurnameCount TO MostPopularCount

  MOVE PrevSurname TO MostPopularSurname

  END-IF.

  CountSurnameOccurs.

  READ CensusFile

  AT END SET EndOfCensusFile TO TRUE

  END-READ.

  Program Notes

  The census file is ordered on ascending Surname in ascending CountyName, and that is the same order required for the printed report. The control items are CountyName and Surname. The data items PrevSurname and PrevCountyName are used to detect the control breaks. Similar to Listing 10-1, the structure of this program echoes the structure of the input file and the output report.

  Test Data and Results

  Figure 10-4 shows the report produced by the program and a small portion of the test data file used.

  217

  Chapter 10 ■ proCessing sequential Files

  Figure 10-4. The report produced by the program, and part of the test data file

  Updating Sequential Files

  It is easy to add records to an unordered sequential file because you can simply add them to the end of the file by opening the file for EXTEND. For instance:

  OPEN EXTEND UnorderedFile

  WRITE UnorderedRec

  When a file is OPENed for EXTEND, the Next Record Pointer is positioned at the end of the file. When records are written to the file, they are appended to the end.

  Although you can add records to an unordered sequential file, the records in a sequential file cannot be deleted or updated in situ. The only way to delete records from a sequential file is to create a new file, which does not contain them; and the only way to update records is to create a new file that contains the updated records. A record update involves changing the value of one or more of its fields. For instance, you might change the value of the CustomerAddress or CustomerPhoneNumber field of a customer record, or you might change the value of the QtyInStock or ReorderLevel field of a stock record.

  ■ COBOL Detail although, in standard CoBol, sequential files cannot be deleted or updated in situ many vendors, including Micro Focus, allow this for disk-based files.

  218

  Chapter 10 ■ proCessing sequential Files

  Because updating or deleting records in a sequential file requires you to read all the records in the file and to create a new file that has the changes applied to it, it is computationally too expensive to apply these operations to the file one at a time. Updates to sequential files are normally done in batch mode. That is, all the updates are gathered together into what is often referred to as the transaction file and then applied to the target file in one go or batch. The target file is often referred to as the master file.

  As you have seen, you can add records to an unordered sequential file by opening the file for EXTEND and writing the records to the end of it. But if you want to update or delete records, you must have a way of identifying the record you want to update or delete. A key field is normally used to achieve this. A key field is a field in the record whose value can be used to identify that record. For instance, in a stock record, the StockNumber might be used as the key field.

  When you apply transaction records to a master file, you compare the key field in the transaction record with that in the master file record. If there is a match, you can apply the delete or update to that master file record. This key-comparison operation is called record matching.

  For record matching to work correctly, the transaction file and the master file must be ordered on the same key value. Record matching does not work if either file is unordered or if the files are ordered on different key fields. If you need convincing of this, PERFORM (that is, go there, do the exercise, and then come back) the Language Knowledge Exercise at the end of the chapter. That exercise will help you understand the problems of trying to apply batched transactions to an unordered master file.

  Applying Transactions to an Ordered Sequential File

  You start this section by looking at programming templates that show how to apply each type of transaction (insertion, deletion, and update) to an ordered sequential file. To c
omplicate matters, most transaction files consist of a mixture of transaction types. Therefore, this section considers the data-declaration implications of mixed transaction types, and you examine an example program that applies a variety of transaction types to an ordered sequential file.

  Inserting Records in an Ordered Sequential File

  When you want to add records to an unordered sequential file, you just OPEN the file for EXTEND and then write the records to the file. You can’t do that with an ordered sequential file because if you do, the records will no longer be in order.

  When you insert records into an ordered sequential file, a major consideration must be to preserve the ordering.

  To insert records, you must create a new file that consists of all the records of the old file with the new records inserted into their correct key-value positions. When you are inserting records into an ordered file, you also have to be aware of the possibility that the record you are trying to insert will have the same key value as one already in the file. This is an error condition. For instance, you can’t have two customer records with the same CustomerId value.

  Figure 10-5 is a template that outlines the algorithm required to insert records from an ordered transaction file into their correct positions in an ordered master file. There are three files. The transaction file (TF) contains the three records you want to insert. The master file (MF) is the file into which you wish to insert these records. Because the MF

  is a sequential file, the only way to insert the records is to create a new file that contains the inserted records. This is the new master file (NMF).

  219

  Chapter 10 ■ proCessing sequential Files

  Figure 10-5. Inserting records into an ordered sequential file

  The program starts by opening the files and reading a record from each of the two input files. This is the equivalent of the read-ahead technique that you saw in Chapter 5. Before you enter the loop that processes the files, you start with a record in each file buffer. The loop is executed until the end of both files, because regardless of which file ends first, the remaining records of the other must be written to the NMF.

 

‹ Prev