Michael Coughlan

Home > Other > Michael Coughlan > Page 32


  01 BranchSalesRec.

  88 EndOfSalesFile VALUE HIGH-VALUES.

  02 BranchId PIC 9(7).

  02 StateNum PIC 99.

  02 CandySales PIC 9(7)V99.

  To save file space, a two-digit numeric value is used to represent the state instead of a state name.

  249

  Chapter 11 ■ Creating tabular Data

  The program to perform this task is very simple. All you have to do is set up a variable to hold the total candy sales and then add CandySales from each record to TotalCandySales. A fragment of the program required to do this is given in Example 11-1.

  Example 11-1. PROCEDURE DIVISION of a Program to Sum Total Candy Sales

  PROCEDURE DIVISION.

  Begin.

  OPEN INPUT SalesFile

  READ SalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ

  PERFORM UNTIL EndOfSalesFile

  ADD CandySales TO TotalCandySales

  READ SalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ

  END-PERFORM.

  DISPLAY "Total candy sales for the US : ", TotalCandySales

  CLOSE SalesFile

  STOP RUN.

  Second Specification

  The program to solve the problem set in the first specification is simple. But suppose the specification is changed so that instead of being asked for the country’s total candy sales, you are asked to calculate the total sales for each state.

  One approach to this new problem would be to sort the file on StateNum. This would turn the requirement into a simple control-break problem (that is, process all the records for one state, output the result, and then go on to the next). But the issue with this solution is that sorting is a comparatively slow, disk-intensive procedure. You want to avoid having to adopt this solution if possible. Is there any other way to solve the problem?

  You could create 50 variables (one for each state) to hold the sales totals. Then, in the program, you could use an EVALUATE statement to add CandySales to the appropriate total. For example:

  EVALUATE StateNum

  WHEN 1 ADD CandySales TO State1SalesTotal

  WHEN 2 ADD CandySales TO State2SalesTotal

  WHEN 3 ADD CandySales TO State3SalesTotal

  ..... 47 more WHEN branches

  END-EVALUATE

  This solution is not very satisfactory. You need a specific WHEN branch to process each state, and you have to declare 50 data items to hold the sales totals. And when you want to display the results, you must use 50 DISPLAY

  statements:

  DISPLAY "State 1 total is ", State1SalesTotal

  DISPLAY "State 2 total is ", State2SalesTotal

  DISPLAY "State 3 total is ", State3SalesTotal

  ..... 47 more DISPLAY statements

  250

  Chapter 11 ■ Creating tabular Data

  But this poor attempt at a solution does contain the germ of an idea of how to solve the problem. It is interesting to note that the processing of each WHEN branch is the same: CandySales is added to the sales total for a particular state. You could replace all 50 WHEN branches with one statement if you could generalize to something like this: ADD the CandySales to the StateSalesTotal location indicated by the StateNum.

  There is also something interesting about the 50 data items. They all have exactly the same PICTURE, and

  they all have, more or less, the same name: StateSalesTotal. The only way you can distinguish between one

  StateSalesTotal and another is by attaching a number to the name: State1SalesTotal, State2SalesTotal,

  State3SalesTotal, and so on.

  When you see a group of data items that all have the same name and the same description and are only

  distinguished from one another by a number attached to the name, you know that you have a problem crying out for a table-based solution.

  Using a Table for the State Sales Totals

  In COBOL, you declare a table by specifying the type (or structure) of a single item (element) of the table and then specifying that the data item is to be repeated a given number of times. For instance, StateSalesTable may be defined as follows:

  01 StateSalesTable.

  02 StateSalesTotal PIC 9(8)V99 OCCURS 50 TIMES.

  StateSalesTable can be represented diagrammatically as shown in Figure 11-1. All the elements of the table have the name StateSalesTotal; you can refer to a specific one by using that name followed by an integer value in brackets. So, StateSalesTotal(3) refers to the third element of the table, and StateSalesTotal(13) refers to the thirteenth element.

  Figure 11-1. Diagrammatic representation of StateSalesTable

  But when you refer to an element, you don’t have to use a numeric literal. You can use anything that evaluates to a numeric value between 1 and the size of the table—even a simple arithmetic expression.

  So the solution to the problem of summing the candy sales for each state is to use a table to hold a

  StateSalesTotal for each state and to use StateNum to access the correct element in the table.

  Once you realize that you can use a table to hold the sales totals and StateNum as an index into the table, the solution to the problem becomes very simple. A program to read the sales file, sum the sales, and display the results is given in Listing 11-1. In this example, to keep the program simple and focus on table creation and handling, I chose to display the results rather than write them to a print file.

  251

  Chapter 11 ■ Creating tabular Data

  Listing 11-1. Summing Candy Sales for Each State

  IDENTIFICATION DIVISION.

  PROGRAM-ID. Listing11-1.

  AUTHOR. Michael Coughlan

  * Program to sum the CandySales for each branch of YoreCandyShoppe

  * and display the results in StateNum order

  * Using as input the Sequential BranchSalesFile ordered on ascending BranchId

  ENVIRONMENT DIVISION.

  INPUT-OUTPUT SECTION.

  FILE-CONTROL.

  SELECT BranchSalesFile ASSIGN TO "Listing11-1BranchSales.dat"

  ORGANIZATION IS LINE SEQUENTIAL.

  DATA DIVISION.

  FILE SECTION.

  FD BranchSalesFile.

  01 BranchSalesRec.

  88 EndOfSalesFile VALUE HIGH-VALUES.

  02 BranchId PIC 9(7).

  02 StateNum PIC 99.

  02 CandySales PIC 9(7)V99.

  WORKING-STORAGE SECTION.

  01 StateSalesTable.

  02 StateSalesTotal PIC 9(8)V99 OCCURS 50 TIMES.

  01 StateIdx PIC 99.

  01 PrnStateSales PIC $$$,$$$,$$9.99.

  PROCEDURE DIVISION.

  Begin.

  MOVE ZEROS TO StateSalesTable

  OPEN INPUT BranchSalesFile

  READ BranchSalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ

  PERFORM UNTIL EndOfSalesFile

  ADD CandySales TO StateSalesTotal(StateNum)

  READ BranchSalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ

  END-PERFORM

  DISPLAY " YoreCandyShoppe Sales by State"

  DISPLAY " ------------------------------"

  PERFORM VARYING StateIdx FROM 1 BY 1

  UNTIL StateIdx GREATER THAN 50

  MOVE StateSalesTotal(StateIdx) TO PrnStateSales

  252

  Chapter 11 ■ Creating tabular Data

  DISPLAY "State ", StateIdx

  " sales total is " PrnStateSales

  END-PERFORM

  CLOSE BranchSalesFile

  STOP RUN.

  Third Specification: Group Items as Table Elements

  The elements of a table do not have to be elementary items. An element can be a group item. In other words, each element can be subdivided into two or more subordinate items.

  Suppose the specification of the YoreCandyShoppe sales-report program chan
ges so that in addition to

  summing the candy sales for each state, the program should count the number of branches and compute the average sales for the state. Final country totals should also be produced, showing Total-US-Sales, US-BranchCount, and Average-US-Sales.

  One solution to this problem would be to set up two separate tables: one to hold state sales and another to hold the count of the number of branches in the state (see Example 11-2).

  Example 11-2. The Two-Table Solution

  01 StateSalesTable.

  02 StateSalesTotal PIC 9(8)V99 OCCURS 50 TIMES.

  01 StateBranchesTable.

  02 StateBranchCount PIC 9(5) OCCURS 50 TIMES.

  Then all that would be required to calculate the average sales for the state would be a statement such as

  COMPUTE AverageStateSales = StateSalesTotal(StateNum) / StateBranchCount(StateNum)

  This is probably the way you would solve the problem in most languages. But in COBOL you can also set

  up a single table in which each element is defined as a group item that consists of the StateSalesTotal and the StateBranchCount (see Example 11-3).

  Example 11-3. Solution Using the Group Item as a Table Element

  01 StateSalesTable.

  02 StateTotals OCCURS 50 TIMES.

  03 StateSalesTotal PIC 9(8)V99.

  03 StateBranchCount PIC 9(5).

  To calculate the average sales, you can use the same COMPUTE statement as before:

  COMPUTE AverageStateSales = StateSalesTotal(StateNum) / StateBranchCount(StateNum)

  A diagrammatic representation of this table description is shown in Figure 11-2. Each element of the table now consists of two parts: StateSalesTotal and StateBranchCount. These are subordinate to the StateTotals element.

  Data-manipulation opportunities abound. All these data names allow you to manipulate the data in the table at different levels of granularity. You can use the following commands:

  • MOVE ZEROS TO StateSalesTable: See Figure 11-2. Fills the whole table with zeros.

  • MOVE StateTotals(2) TO StateTotals(5): See Figure 11-2. Copies the contents of one

  element, including both subordinate items, to another element.

  253

  Chapter 11 ■ Creating tabular Data

  • DISPLAY StateBranchCount(3): Displays the contents of the StateBranchCount part of

  element 3.

  • ADD CandySales TO StateSalesTotal(3): Adds CandySales to the contents of the

  StateSalesTotal part of element 3.

  Figure 11-2. Table elements as group items. Element 3 is exploded to show details

  Tabular Data Program

  Listing 11-2 is a solution to the problem posed by the changed specification. It uses the table defined in Example 11-3.

  Listing 11-2. Table Elements as Group Items

  IDENTIFICATION DIVISION.

  PROGRAM-ID. Listing11-2.

  AUTHOR. Michael Coughlan

  * Program that for each state and for the whole US

  * sums the CandySales for each branch of YoreCandyShoppe

  * counts the number of branches

  * calculates the average sales per state and displays the results in StateNum order

  * Uses as input the Sequential BranchSalesFile ordered on ascending BranchId

  ENVIRONMENT DIVISION.

  INPUT-OUTPUT SECTION.

  FILE-CONTROL.

  SELECT BranchSalesFile ASSIGN TO "Listing11-2BranchSales.dat"

  ORGANIZATION IS LINE SEQUENTIAL.

  DATA DIVISION.

  FILE SECTION.

  FD BranchSalesFile.

  01 BranchSalesRec.

  88 EndOfSalesFile VALUE HIGH-VALUES.

  02 BranchId PIC 9(7).

  02 StateNum PIC 99.

  02 CandySales PIC 9(7)V99.

  254

  Chapter 11 ■ Creating tabular Data

  WORKING-STORAGE SECTION.

  01 StateSalesTable.

  02 StateTotals OCCURS 50 TIMES.

  03 StateSalesTotal PIC 9(8)V99.

  03 StateBranchCount PIC 9(5).

  01 StateIdx PIC 99.

  01 ReportHeading1 PIC X(35)

  VALUE " YoreCandyShoppe Sales by State".

  01 ReportHeading2 PIC X(35)

  VALUE " ------------------------------".

  01 ReportHeading3 PIC X(47)

  VALUE "State Branches StateSales AverageSales".

  01 DetailLine.

  02 PrnStateNum PIC BZ9.

  02 PrnBranchCount PIC B(3)ZZ,ZZ9.

  02 PrnStateSales PIC B(5)$$$,$$$,$$9.99.

  02 PrnAveageSales PIC BB$$$,$$$,$$9.99.

  01 US-Totals.

  02 US-TotalSales PIC 9(9)V99.

  02 US-BranchCount PIC 9(6).

  02 PrnUS-TotalSales PIC $,$$$,$$$,$$9.99.

  02 PrnUS-BranchCount PIC B(9)ZZZ,ZZ9.

  02 PrnUS-AverageSales PIC BBBB$$$,$$$,$$9.99.

  PROCEDURE DIVISION.

  Begin.

  MOVE ZEROS TO StateSalesTable

  OPEN INPUT BranchSalesFile

  READ BranchSalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ

  PERFORM UNTIL EndOfSalesFile

  ADD CandySales TO StateSalesTotal(StateNum), US-TotalSales

  ADD 1 TO StateBranchCount(StateNum), US-BranchCount

  READ BranchSalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-READ

  END-PERFORM

  PERFORM PrintResults

  CLOSE BranchSalesFile

  STOP RUN.

  PrintResults.

  DISPLAY ReportHeading1

  DISPLAY ReportHeading2

  255

  Chapter 11 ■ Creating tabular Data

  DISPLAY ReportHeading3

  PERFORM VARYING StateIdx FROM 1 BY 1

  UNTIL StateIdx GREATER THAN 50

  MOVE StateIdx TO PrnStateNum

  MOVE StateSalesTotal(StateIdx) TO PrnStateSales

  MOVE StateBranchCount(StateIdx) TO PrnBranchCount

  COMPUTE PrnAveageSales = StateSalesTotal(StateIdx) / StateBranchCount(StateIdx)

  DISPLAY DetailLine

  END-PERFORM

  MOVE US-TotalSales TO PrnUS-TotalSales

  MOVE US-BranchCount TO PrnUS-BranchCount

  COMPUTE PrnUS-AverageSales = US-TotalSales / US-BranchCount

  DISPLAY "YoreCandyShoppe branches in the US = " PrnUS-BranchCount

  DISPLAY "YoreCandyShoppe sales in the US = " PrnUS-TotalSales

  DISPLAY "YoreCandyShoppe average US sales = " PrnAveageSales.

  Multidimensional Tables

  Listing 11-2 uses a table in which each element is a group item that consists of the StateSalesTotal and the StateBranchCount. But the table is still a single-dimensional table. Sometimes the solution to a problem demands a multidimensional table approach. A multidimensional table is one in which each element of the table is itself a table.

  This section considers multidimensional tables in the context of a specification change for the YoreCandyShoppe sales report.

  Suppose each YoreCandyShoppe branch is asked to provide more granular sales data. Instead of reporting sales for the entire year, each branch must now report sales for each month. To do this, the sales record for each branch must be changed to accommodate a 12-element table of sales data. The new record description is given in Example 11-4.

  Example 11-4. New Record Description That Records Candy Sales for Each Month

  01 BranchSalesRec.

  88 EndOfSalesFile VALUE HIGH-VALUES.

  02 BranchId PIC 9(7).

  02 StateNum PIC 99.

  02 SalesForMonth PIC 9(5)V99 OCCURS 12 TIMES.

  The report produced from the sales file must reflect this more granular data and is now required to show the following:

  • Total sales for each state

  • The count of the number of branches in the state

  • Average sales per branch for each state
<
br />   • Sales per month for each state

  • Final country totals showing Total-US-Sales, US-BranchCount, and Average-US-Sales

  In the program that implemented the previous specification, the sales for each state and the number of branches in each state were recorded in a 50-element table. In this version, instead of the total sales for the year, you have to record the sales per month. To do that, you need a two-dimensional table as described in Example 11-5.

  256

  Chapter 11 ■ Creating tabular Data

  Example 11-5. Two-dimensional Table to Record Sales per Month and the Number of Branches in the State 01 StateSalesTable.

  02 State OCCURS 50 TIMES.

  03 StateBranchCount PIC 9(5).

  03 StateMonthSales PIC 9(5)V99 OCCURS 12 TIMES.

  COBOL DetaIL

  if you wanted to manipulate the table at a further level of granularity, you could describe the table as

  01 StateSalesTable.

  02 State OCCURS 50 TIMES.

  03 StateBranchCount PIC 9(5).

  03 StateSales.

  04 StateMonthSales PIC 9(5)V99 OCCURS 12 TIMES.

  The table description in Example 11-5 highlights a difference between COBOL tables and arrays. In other

  languages, two arrays would be required to record this information: a two-dimensional table to record the state sales per month and a one-dimensional table to record the number of branches per state. You can also record the data using two tables in COBOL, as shown in Example 11-6; but COBOL’s hierarchical structuring allows you to combine both tables so that each element of the first dimension consists of the BranchCount and a 12-element table containing the sales for each month.

  Example 11-6. A Two-Table Solution

  01 StateSalesTable.

  02 State OCCURS 50 TIMES.

  03 StateMonthSales PIC 9(5)V99 OCCURS 12 TIMES.

  01 StateBranchesTable.

  02 State OCCURS 50 TIMES.

 

‹ Prev