Multiple-Level Arrays and Tables: Objectives
Multiple-Level Arrays and Tables: Objectives
OBJECTIVES
To familiarize you with
1. How to establish a series of items using a double-level OCCURS clause.
2. How to store data in a double-level or two-dimensional array.
3. How to look up data stored in a double-level or two-dimensional table.
4. How to access and manipulate data defined with a triple-level (or more)
OCCURS clause.
CONTENTS
DOUBLE-LEVEL OCCURS CLAUSE Performing a Full Table Look-Up
Defining a Double-Level or Two-Dimensional Searching Only Part of a Table
Array Searching Elements in an Array
Accessing a Double-Level or Two-Dimensional TRIPLE-LEVEL OCCURS CLAUSE AND MORE
Array END-OF-CHAPTER AIDS
Using Nested PERFORMs Chapter Summary
Using PERFORM ... VARYING ... AFTER Chapter Self-Test
Self-Test Practice Program
Using a Double-Level or Two-Dimensional Review Questions
Array for Accumulating Totals Debugging Exercises
Loading Input Data into a Double-Level or Programming Assignments
Two-Dimensional Array
Self-Test
Performing a Look-Up Using a Double-Level
OCCURS
504 ● Unit 4: Array Processing and Table Handling
When describing an area of storage, more than one level of OCCURS may be used. As
many as seven levels of OCCURS are permitted with COBOL 85, and as many as three
levels are permitted with COBOL 74.
Like a single-level OCCURS, multiple levels of OCCURS may be used for (1) accumu-
lating totals in an array or (2) storing a table for ‘‘look-up’’ purposes. We will look first
at multiple-level arrays and then at multiple-level tables.
The ellipses or dots (...) indicate that 24 elementary items must be coded, which would
be rather cumbersome. Instead, we could use a double-level OCCURS to define the array
as follows:
01 TEMPERATURE-ARRAY.
05 DAY-IN-WEEK OCCURS 7 TIMES.
10 HOUR OCCURS 24 TIMES.
15 TEMP PIC S9(3).
The following illustration shows how this array can be visualized in storage:
Hour TEMPERATURE-ARRAY
24 COLUMNS
Chapter 13: Multiple-Level Arrays and Tables ● 505
For each DAY-IN-WEEK, we have 24 HOUR figures, each of which will consist of a TEMP
(average or mean temperature for that hour) that is three integers long. Thus, this array
defines a storage area of 504 positions (7 2 24 2 3). This two-dimensional array is estab-
lished as follows:
1. The array will have 7 rows as indicated by the first OCCURS clause:
05 DAY-IN-WEEK OCCURS 7 TIMES.
2. Within this array, each row will have 24 columns, as indicated by the second
OCCURS clause:
3. Each of the elements in this 7 2 24 array will be large enough to hold three integers,
as indicated by the subordinate entry:
15 TEMP PIC S9(3).
To access any of the temperature figures, we use the data-name on the lowest OCCURS
level or any data-name subordinate to it. Either TEMP or HOUR could be used to access
the temperatures. Because HOUR contains only one elementary item, TEMP and HOUR refer
to the same area of storage. Thus, the array could also have been defined as follows:
Alternative Coding
01 TEMPERATURE-ARRAY.
05 DAY-IN-WEEK OCCURS 7 TIMES.
10 HOUR OCCURS 24 TIMES PIC S9(3).
We have added the PIC clause to the second OCCURS level data-name, thereby elimi-
nating the reference to the data-name TEMP.
We will use the entry TEMP throughout, however, since it is clearer. Note that we
could not use DAY-IN-WEEK for accessing a single field in the array, since each DAY-IN-
WEEK actually refers to 24 temperatures.
The first subscript can vary from 1 to 7 since there are seven rows, one for each day.
The second subscript varies from 1 to 24, since there are 24 columns, one for each hour
of the day. The following subscripts are not valid:
Invalid Subscripts
TEMP (8, 4) The first subscript can vary from 1 through 7.
TEMP (6, 25) The second subscript can vary from 1 through 24.
Hour Temperature-Array
Example 1 Suppose we wish to print an average temperature for the entire week. We need to add all the
array entries to a total and divide by 168 (7 2 24). We can use nested PERFORMs for this purpose.
The first PERFORM varies the major subscript, which we call DAY-SUB, and the second PERFORM
varies the minor subscript, which we call HOUR-SUB:
600-AVERAGE-RTN.
MOVE 0 TO TOTAL.
PERFORM 700-LOOP-ON-DAYS
VARYING DAY-SUB FROM 1 BY 1 UNTIL DAY-SUB > 7.
COMPUTE WEEKLY-AVERAGE = TOTAL / 168.
WRITE PRINT-REC FROM OUT-REC
AFTER ADVANCING 2 LINES.
700-LOOP-ON-DAYS.
PERFORM 800-LOOP-ON-HOURS
VARYING HOUR-SUB FROM 1 BY 1 UNTIL HOUR-SUB > 24.
800-LOOP-ON-HOURS.
ADD TEMP (DAY-SUB, HOUR-SUB) TO TOTAL.
Chapter 13: Multiple-Level Arrays and Tables ● 507
Using in-line PERFORMs with COBOL 85, we could code the above as:
800-AVERAGE-RTN.
MOVE 0 TO TOTAL.
PERFORM VARYING DAY-SUB FROM 1 BY 1 UNTIL DAY-SUB > 7
PERFORM VARYING HOUR-SUB FROM 1 BY 1 UNTIL HOUR-SUB > 24
ADD TEMP (DAY-SUB, HOUR-SUB) TO TOTAL
END-PERFORM
END-PERFORM.
COMPUTE WEEKLY-AVERAGE = TOTAL / 168.
WRITE PRINT-REC FROM OUT-REC
AFTER ADVANCING 2 LINES.
When using nested in-line PERFORMs, there should be no periods until after the last END-PER-
FORM. A period would be optional after the last END-PERFORM unless it was the last word in the
paragraph.
Expanded Format
PERFORM Fprocedure-name-1 FH J
THROUGH
THRU
procedure-name-2 GG
F WITH TEST H
BEFORE
AFTER JG
VARYING H identifier-2
index-name-1 J 5
FROM
identifier-3
index-name-2
literal-1 6
BY H identifier-4
literal-2 J UNTIL condition-1
F AFTER H identifier-5
index-name-3 J 5
FROM
identifier-6
index-name-4
literal-3 6
BY H identifier-7
literal-4 J UNTIL condition-2G ...
[END-PERFORM]*
*With COBOL 85 only.
This format is particularly useful for processing multiple-level arrays and tables. The
PERFORM ... VARYING varies the major subscript, and the AFTER clause varies the minor
subscript. Thus, we can simplify the preceding nested PERFORM as follows:
Alternative Coding
600-AVERAGE-RTN.
MOVE 0 TO TOTAL.
PERFORM 700-LOOP1
VARYING DAY-SUB FROM 1 BY 1 UNTIL DAY-SUB > 7
AFTER HOUR-SUB FROM 1 BY 1 UNTIL HOUR-SUB > 24.
COMPUTE WEEKLY-AVERAGE = TOTAL / 168.
WRITE PRINT-REC FROM OUT-REC
AFTER ADVANCING 2 LINES.
700-LOOP1.
ADD TEMP (DAY-SUB, HOUR-SUB) TO TOTAL.
508 ● Unit 4: Array Processing and Table Handling
The sequence of values that these subscripts take on is (1, 1), (1, 2) . . . (1, 24), (2, 1),
(2, 2) . . . (2, 24) . . . (7, 1) . . . (7, 24). That is, with the PERFORM ... VARYING ... AFTER,
DAY-SUB is initialized at 1 and HOUR-SUB is varied from 1 to 24. Then DAY-SUB is incre-
mented to 2 and HOUR-SUB is varied again from 1 to 24. This continues until HOUR-SUB
is varied from 1 to 24 with DAY-SUB at 7.
Example 2 Interactive Processing. Suppose we want to enable users to make inquiries from the
TEMPERATURE-ARRAY:
WORKING-STORAGE SECTION.
01 WS-DAY PIC 9.
01 WS-HOUR PIC 99.
.
.
.
DISPLAY ’ENTER DAY OF WEEK (1 = SUN,...7 = SAT)’.
ACCEPT WS-DAY.
DISPLAY ’ENTER HOUR (1 = 1 A.M.,...24 = MIDNIGHT)’.
ACCEPT WS-HOUR.
DISPLAY ’THE TEMPERATURE IS ’, TEMP (WS-DAY, WS-HOUR).
Example 3 Consider the following double-level array and assume that data has been read into it:
01 POPULATION-ARRAY.
05 STATE OCCURS 50 TIMES.
10 COUNTY OCCURS 10 TIMES.
15 POPULATION PIC 9(10).
This array defines 500 fields of data or 5000 characters. Each of the 50 states is divided into 10
counties, each with 10 characters. We have arbitrarily selected 10 counties per state, each with a
POPULATION of 9(10), for illustration purposes only. In reality, the number of counties per state
varies from state to state, and counties will have populations that have fewer than 10 digits.
A pictorial representation of the array is as follows:
County POPULATION-ARRAY
Suppose we wish to accumulate a total United States population. We will add all 10 counties
for each of 50 states. We access elements in the array by using the lowest level item, POPULATION.
POPULATION must be accessed using two subscripts. The first defines the major level, STATE, and
the second defines the minor level, COUNTY. POPULATION (5, 10) refers to the population for
STATE 5, COUNTY 10. The first subscript varies from 1 to 50; the second varies from 1 to 10.
To perform the required addition, we will first accumulate all COUNTY figures for STATE 1.
Thus, the second or minor subscript will vary from 1 to 10. After 10 additions for STATE 1 are
performed, we will accumulate the 10 COUNTY figures for STATE 2. That is, we will increment the
major subscript to 2 and then add COUNTY (2, 1), COUNTY (2, 2), ... COUNTY (2, 10) before
we add the figures for STATE 3.
The required operations may be performed in two ways:
PERFORM 700-USA-TOT.
.
.
.
700-USA-TOT.
PERFORM 800-MAJOR-LOOP
VARYING STATE-SUB FROM 1 BY 1 UNTIL STATE-SUB > 50.
PERFORM 1000-PRINT-TOTAL.
800-MAJOR-LOOP.
PERFORM 900-MINOR-LOOP
VARYING COUNTY-SUB FROM 1 BY 1 UNTIL COUNTY-SUB > 10.
900-MINOR-LOOP.
ADD POPULATION (STATE-SUB, COUNTY-SUB) TO TOTAL1.
.
.
.
Alternative Coding
PERFORM 700-USA-TOT.
.
.
.
700-USA-TOT.
PERFORM 800-ADD-POP
VARYING STATE-SUB FROM 1 BY 1 UNTIL STATE-SUB > 50
AFTER COUNTY-SUB FROM 1 BY 1 UNTIL COUNTY-SUB > 10.
PERFORM 1000-PRINT-TOTAL.
800-ADD-POP.
ADD POPULATION (STATE-SUB, COUNTY-SUB) TO TOTAL1.
The following illustrates how this procedure could be coded using an in-line
PERFORM:
Using either routine, we vary the minor subscript first, holding the major subscript
constant. That is, when the major subscript is equal to 1, denoting STATE 1, all counties
within that STATE are summed. Thus, we set STATE-SUB equal to 1 and vary COUNTY-
SUB from 1 to 10. STATE-SUB is then set to 2, and we again vary COUNTY-SUB from 1 to
10, and so on.
The sequence of additions may also be performed as follows: POPULATION (1, 1),
POPULATION (2, 1), ... POPULATION (50, 1); POPULATION (1, 2), POPULATION
(2, 2), ... POPULATION (50, 2), ... POPULATION (50, 10). That is, we can add
the population figures for COUNTY 1 in all 50 states, then COUNTY 2 in all 50 states, and
so on. This means we vary the major subscript first, holding the minor subscript constant.
We set COUNTY-SUB equal to 1 and vary STATE-SUB from 1 to 50; we then increment
510 ● Unit 4: Array Processing and Table Handling
COUNTY-SUB to 2 and vary STATE-SUB from 1 to 50 again, and so on. The following
coding illustrates how this procedure can be performed:
Alternative Coding
PERFORM 700-USA-TOT.
.
.
.
700-USA-TOT.
PERFORM 800-MAJOR-LOOP
VARYING COUNTY-SUB FROM 1 BY 1 UNTIL COUNTY-SUB > 10.
PERFORM 1000-PRINT-TOTAL.
800-MAJOR-LOOP.
PERFORM 900-MINOR-LOOP
VARYING STATE-SUB FROM 1 BY 1 UNTIL STATE-SUB > 50.
900-MINOR-LOOP.
ADD POPULATION (STATE-SUB, COUNTY-SUB) TO TOTAL1.
All the routines illustrated result in the same accumulated population total.
Example 4 Let us establish an array that will contain 12 monthly totals for each of 25 salespeople in Lacy’s
Department Store. Each total represents the accumulated monthly sales amount transacted by a
salesperson. Thus, the first element in the array will be January’s sales total for Salesperson 1,
the second will be February’s sales total for Salesperson 1, and so on.
There are 25 salespeople, each having 12 monthly sales totals, and the salespeople are num-
bered from 1 to 25 consecutively. The WORKING-STORAGE SECTION entry for this array is as follows:
01 COMPANY-SALES-ARRAY.
05 SALESPERSON OCCURS 25 TIMES.
10 MONTH-AMT OCCURS 12 TIMES PIC 9(4).
The major-level OCCURS clause indicates that there are 25 salespeople represented in the array.
Each of the 25 salespeople has 12 monthly sales totals. Thus the array has 300 fields, each four
positions long. We need not store month number or salesperson number since both vary consec-
utively: the former from 1 to 12 and the latter from 1 to 25. This array, then, is a direct-referenced
array.
Assume that data has already been stored in the array. We wish to print 12 lines of monthly
totals. Each line will contain 25 totals, one for each salesperson. Line 1 will contain 25 sales figures
for January. These include array elements (1, 1) ... (25, 1) or the January totals for sales-
persons 1 through 25. Line 2 will contain 25 sales totals for February, which would be (1, 2)
... (25, 2), and so on.
The format of each line to be printed is described in WORKING-STORAGE as follows:
WORKING-STORAGE SECTION.
01 SALES-LINE.
The word FILLER is required 05 PIC X.
with COBOL 74 05 ITEMX OCCURS 25 TIMES.
10 MONTHLY-SALESPERSON-TOTAL PIC ZZZ9.
10 PIC X.
05 PIC X(6).
We use a single-level OCCURS clause to describe the 25 sales totals within SALES-LINE. Since
each line will contain 25 salesperson figures, only one OCCURS clause is necessary. The fact that
there will be 12 lines printed is not denoted by an OCCURS clause, but by repeating the print
routine 12 times. OCCURS clauses are used to denote repeated occurrences of fields, not records.
Note that ITEMX, which OCCURS 25 TIMES, consists of two fields, MONTHLY-SALESPERSON-TOTAL
and a one-position blank or FILLER area. This one-position area will separate each of the 25
amount fields to make the entire line more readable. If all the monthly salesperson totals
appeared next to one another, it would be difficult to read the line.
Using a nested PERFORM, the routine is as follows:
PERFORM 800-WRITE-RTN
VARYING SUB2 FROM 1 BY 1 UNTIL SUB2 > 12.
.
.
.
800-WRITE-RTN.
MOVE SPACES TO SALES-LINE.
Chapter 13: Multiple-Level Arrays and Tables ● 511
PERFORM 900-MOVE-RTN
VARYING SUB1 FROM 1 BY 1 UNTIL SUB1 > 25.
WRITE PRINT-REC FROM SALES-LINE
AFTER ADVANCING 2 LINES.
900-MOVE-RTN.
MOVE MONTH-AMT (SUB1, SUB2) TO MONTHLY-SALESPERSON-TOTAL (SUB1).
What we have done is to take an array that consists of 25 rows and 12 columns and print it out
in an order different from the one in which it is stored:
MONTH COMPANY-SALES-ARRAY
SALESPERSON 1 2 3 4 5 6 7 8 9 10 11 12
1
Sales for Sales for
2 salesperson 1 salesperson 25
SALES FOR
MONTH 1
• • • •
• •
• •
SALES FOR •
MONTH 12
• • •
25
We use the same subscript, SUB1, to reference the number of the salesperson accessed in
(1) COMPANY-SALES-ARRAY and in (2) the print line.
In the next section, we will consider how to ADD to fields in the array. We end that
section with the program that produces the output specified above.
SELF-TEST Using the following TEMPERATURE-ARRAY, code the solutions to Questions 1–5:
01 TEMPERATURE-ARRAY.
05 DAY-IN-WEEK OCCURS 7 TIMES.
10 HOUR OCCURS 24 TIMES.
15 TEMP PIC S9(3).
MOVE 0 TO TOTAL.
PERFORM VARYING X2 FROM 1 BY 1
UNTIL X2 > 24
ADD TEMP (1, X2) TO TOTAL
END-PERFORM.
COMPUTE AVERAGE = TOTAL / 24.
DISPLAY ’AVERAGE TEMPERATURE FOR SUNDAY WAS ’, AVERAGE.
2. MOVE 0 TO TOTAL.
PERFORM 2-AM-AVERAGE
VARYING X1 FROM 1 BY 1 UNTIL X1 > 7.
COMPUTE AVERAGE = TOTAL / 7.
DISPLAY ’THE AVERAGE TEMPERATURE AT 2 AM WAS ’, AVERAGE.
.
.
.
2-AM-AVERAGE.
ADD TEMP (X1, 2) TO TOTAL.
MOVE 0 TO TOTAL.
PERFORM VARYING X1 FROM 1 BY 1
UNTIL X1 > 7
ADD TEMP (X1, 2) TO TOTAL
END-PERFORM.
COMPUTE AVERAGE = TOTAL / 7.
DISPLAY ’THE AVERAGE TEMPERATURE AT 2 AM WAS ’, AVERAGE.
We could replace the first PERFORM with the following and eliminate 200-MAJOR-LOOP
entirely:
PERFORM 300-MINOR-LOOP
VARYING X1 FROM 1 BY 1 UNTIL X1 > 7
AFTER X2 FROM 1 BY 1 UNTIL X2 > 24.
4. MOVE 0 TO COUNTER.
PERFORM 200-MAJOR-LOOP
VARYING X1 FROM 1 BY 1 UNTIL X1 > 7.
DISPLAY ’NUMBER OF DAYS WHEN TEMPERATURE < 32 WAS ’,
. COUNTER.
.
.
200-MAJOR-LOOP.
MOVE ’NO ’ TO FOUND.
PERFORM 300-MINOR-LOOP
VARYING X2 FROM 1 BY 1 UNTIL X2 > 24 OR
FOUND = ’YES’.
300-MINOR-LOOP.
IF TEMP (X1, X2) < 32
ADD 1 TO COUNTER
MOVE ’YES’ TO FOUND
END-IF.
5. Note: Use 01 DAYS established for Question 3 if an abbreviation for the day (SUN ... SAT)
is to print rather than the day number.
PERFORM 500-PRINT-RTN
VARYING X1 FROM 1 BY 1 UNTIL X1 > 7.
.
.
.
500-PRINT-RTN.
MOVE 0 TO TOTAL.
PERFORM 600-MINOR-LOOP
VARYING X2 FROM 1 BY 1 UNTIL X2 > 24.
MOVE DAY-OF-THE-WEEK (X1) TO DAY-OUT.
COMPUTE AVERAGE-OUT = TOTAL / 24.
WRITE PRINT-REC FROM OUT-REC
AFTER ADVANCING 2 LINES.
600-MINOR-LOOP.
ADD TEMP (X1, X2) TO TOTAL.
6. 01 COMPANY-SALES-ARRAY.
05 SALESPERSON OCCURS 25 TIMES.
10 NAME PIC X(20).
10 MONTHLY-AMT OCCURS 12 TIMES PIC 9(4).
514 ● Unit 4: Array Processing and Table Handling
Suppose a company has 10 departments and five salespeople (numbered 1–5) within
each department. We wish to accumulate the total amount of sales for each salesperson
within each department:
01 DEPT-TOTALS.
05 DEPT OCCURS 10 TIMES.
10 SALESPERSON OCCURS 5 TIMES.
15 TOTAL-SALES PIC 9(5)V99.
Before adding any data to a total area, we must ensure that the total area is initialized
at zero. To initialize an entire array at zero, we could code the following with COBOL
85: MOVE ZEROS TO DEPT-TOTALS. Alternatively, with COBOL 85 we can code:
PERFORM 700-INITIALIZE-RTN
VARYING X1 FROM 1 BY 1 UNTIL X1 > 10
AFTER X2 FROM 1 BY 1 UNTIL X2 > 5.
.
.
.
700-INITIALIZE-RTN.
MOVE 0 TO TOTAL-SALES (X1, X2).
This routine, which initializes each TOTAL-SALES field separately, will run on all
computers; COBOL 85 compilers, however, will allow you to code MOVE ZEROS TO
DEPT-TOTALS.
Assume an input record has been created each time a salesperson makes a sale. Each
input record contains a department number called DEPT-IN, a salesperson number
called SALESPERSON-NO-IN, and an amount of sales called AMT-IN. There may be nu-
merous input records for a salesperson if he or she made more than one sale. The coding
to accumulate the totals after the array has been initialized at zero is as follows:
READ SALES-FILE
AT END MOVE ’NO ’ TO ARE-THERE-MORE-RECORDS
END-READ.
PERFORM 200-ADD-RTN
UNTIL ARE-THERE-MORE-RECORDS = ’NO ’.
.
.
.
200-ADD-RTN.
ADD AMT-IN TO TOTAL-SALES (DEPT-IN, SALESPERSON-NO-IN).
READ SALES-FILE
AT END MOVE ’NO ’ TO ARE-THERE-MORE-RECORDS
END-READ.
As indicated previously, input fields may be used as subscripts. For correct process-
ing, a validation procedure should be used to ensure that (1) DEPT-IN is an integer
between 1 and 10 and (2) SALESPERSON-NO-IN is an integer between 1 and 5. We should
also check that AMT-IN is numeric:
200-ADD-RTN.
IF AMT-IN IS NUMERIC
AND (DEPT-IN >= 1 AND <= 10)
AND (SALESPERSON-NO-IN >= 1 AND <= 5)
Chapter 13: Multiple-Level Arrays and Tables ● 515
At the end of the job, we wish to print 10 pages of output. Each page will contain
five lines, one for each salesperson in a given department. The full PROCEDURE DIVISION
is as follows:
PROCEDURE DIVISION.
100-MAIN-MODULE.
OPEN INPUT SALES-FILE
OUTPUT PRINT-FILE.
MOVE ZEROS TO DEPT-TOTALS.
READ SALES-FILE
AT END MOVE ’NO ’ TO ARE-THERE-MORE-RECORDS
END-READ.
PERFORM 200-ADD-RTN
UNTIL NO-MORE-RECORDS.
PERFORM 300-PRINT-RTN
VARYING X1 FROM 1 BY 1 UNTIL X1 > 10.
CLOSE SALES-FILE
PRINT-FILE.
STOP RUN.
200-ADD-RTN.
*************************************************************
* NOTE: AMT-IN, DEPT-IN, SALESPERSON-NO-IN ARE INPUT FIELDS *
*************************************************************
IF AMT-IN IS NUMERIC
AND (DEPT-IN >= 1 AND <= 10)
AND (SALESPERSON-NO-IN >= 1 AND <= 5)
ADD AMT-IN TO TOTAL-SALES (DEPT-IN, SALESPERSON-NO-IN)
ELSE
DISPLAY ’ERROR’
END-IF.
READ SALES-FILE
AT END MOVE ’NO ’ TO ARE-THERE-MORE-RECORDS
END-READ.
300-PRINT-RTN.
MOVE X1 TO DEPT-NO-ON-HDG-LINE.
WRITE PRINT-REC FROM HDG-LINE
AFTER ADVANCING PAGE.
PERFORM 400-LINE-PRINT
VARYING X2 FROM 1 BY 1 UNTIL X2 > 5.
400-LINE-PRINT.
MOVE X2 TO SALESPERSON-NO-OUT.
MOVE TOTAL-SALES (X1, X2) TO TOTAL-OUT.
WRITE PRINT-REC FROM SALES-LINE-REC
AFTER ADVANCING 2 LINES.
In this illustration, we assume that the values for DEPT-IN vary from 1–10 and the
values for SALESPERSON-NO-IN vary from 1–5. If either or both of these fields have
values other than 1–10 or 1–5 consecutively, then the numbers themselves must be
stored along with the TOTAL-SALES.
In the preceding section we considered a program that is to print 12 monthly sales
totals for 25 salespeople (see p. 510). The input consists of transaction records for the
previous year, each with the following format:
SALESPERSON SALES
NO AMOUNT DATE
MO DA YR
1 2 3 5 6 11
516 ● Unit 4: Array Processing and Table Handling
The full program for printing monthly sales totals that uses procedures discussed in
this section appears in Figure 13.1.
Figure 13.1 IDENTIFICATION DIVISION.
Program to print monthly PROGRAM-ID. FIG131.
sales totals. ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SALES-FILE ASSIGN TO ’S1.DAT’.
SELECT REPORT-FILE ASSIGN TO PRINTER ’P1.OUT’.
DATA DIVISION.
FILE SECTION.
FD SALES-FILE
LABEL RECORDS ARE STANDARD.
01 SALES-REC.
05 SALESPERSON-NO-IN PIC 99.
05 SALES-AMT-IN PIC 999.
05 DATE-OF-TRANS.
10 MONTH-IN PIC 99.
10 DAY-IN PIC 99.
10 YEAR-IN PIC 99.
FD REPORT-FILE
LABEL RECORDS ARE OMITTED.
01 PRINT-REC PIC X(132).
WORKING-STORAGE SECTION.
01 MORE-RECS PIC X(3) VALUE ’YES’.
01 COMPANY-SALES-ARRAY.
05 SALESPERSON OCCURS 25 TIMES.
10 MONTH-AMT OCCURS 12 TIMES PIC 9(4).
01 HEADING-REC.
05 PIC X(30)
VALUE SPACES.
05 PIC X(102)
VALUE ’ANNUAL SALES REPORT’.
01 COLUMN-HEADING.
05 PIC X(43)
VALUE ’ S1 S2 S3 S4 S5 S6 S7 S8 ’.
05 PIC X(39)
VALUE ’S9 S10 S11 S12 S13 S14 S15 S16 ’.
05 PIC X(50)
VALUE ’S17 S18 S19 S20 S21 S22 S23 S24 S25’.
01 SALES-LINE.
05 PIC X.
05 ITEMX OCCURS 25 TIMES.
10 SALES-ITEM PIC ZZZ9.
10 PIC X.
05 PIC X(6).
01 SUB1 PIC 99.
01 SUB2 PIC 99.
PROCEDURE DIVISION.
100-MAIN.
OPEN INPUT SALES-FILE
OUTPUT REPORT-FILE.
WRITE PRINT-REC FROM HEADING-REC
AFTER ADVANCING PAGE.
WRITE PRINT-REC FROM COLUMN-HEADING
AFTER ADVANCING 3 LINES.
MOVE ZEROS TO COMPANY-SALES-ARRAY.
READ SALES-FILE
AT END MOVE ’NO ’ TO MORE-RECS
END-READ.
PERFORM 200-CALC-RTN
UNTIL MORE-RECS = ’NO ’.
PERFORM 800-WRITE-RTN
VARYING SUB2 FROM 1 BY 1 UNTIL SUB2 > 12.
CLOSE SALES-FILE
REPORT-FILE.
Chapter 13: Multiple-Level Arrays and Tables ● 517
STOP RUN.
200-CALC-RTN.
IF MONTH-IN >= 1 AND <= 12
AND SALESPERSON-NO-IN >= 1 AND <= 25
ADD SALES-AMT-IN TO
MONTH-AMT (SALESPERSON-NO-IN, MONTH-IN)
ELSE
DISPLAY ’ERROR ’, SALES-REC
END-IF.
READ SALES-FILE
AT END MOVE ’NO ’ TO MORE-RECS
END-READ.
800-WRITE-RTN.
MOVE SPACES TO SALES-LINE.
PERFORM 900-MOVE-RTN
VARYING SUB1 FROM 1 BY 1 UNTIL SUB1 > 25.
WRITE PRINT-REC FROM SALES-LINE
AFTER ADVANCING 2 LINES.
900-MOVE-RTN.
MOVE MONTH-AMT (SUB1, SUB2) TO SALES-ITEM (SUB1).
To load data such as temperatures or populations into an array, we may use a READ
statement and then move the data to the array. In place of READ and MOVE statements,
we could use a READ ... INTO.
Consider again our TEMPERATURE-ARRAY from the beginning of this chapter:
01 TEMPERATURE-ARRAY.
05 DAY-IN-WEEK OCCURS 7 TIMES.
10 HOUR OCCURS 24 TIMES.
15 TEMP PIC S9(3).
Suppose we have seven input records, each with 24 three-position hourly tempera-
tures. The first input record to be loaded into the array is for Day 1 or Sunday, the
second is for Day 2 or Monday, and so on:
FD TEMP-FILE
LABEL RECORDS ARE OMITTED.
01 IN-REC.
05 HOURLY-TEMP OCCURS 24 TIMES PIC S9(3).
The ARRAY-LOAD routine could be executed as follows. We use subscript names here
that are more meaningful than X1 and X2:
READ TEMP-FILE
AT END PERFORM 600-ERR-RTN
END-READ.
PERFORM 200-ARRAY-LOAD
VARYING DAY-SUB FROM 1 BY 1 UNTIL DAY-SUB > 7
OR NO-MORE-RECORDS.
IF ARE-THERE-MORE-RECORDS = ’YES’ OR DAY-SUB NOT > 7
PERFORM 600-ERR-RTN
END-IF.
.
.
.
200-ARRAY-LOAD.
PERFORM 300-MINOR-LOAD
VARYING HOUR-SUB FROM 1 BY 1 UNTIL HOUR-SUB > 24.
READ TEMP-FILE
AT END MOVE ’NO ’ TO ARE-THERE-MORE-RECORDS
END-READ.
300-MINOR-LOAD.
MOVE HOURLY-TEMP (HOUR-SUB) TO
TEMP (DAY-SUB, HOUR-SUB).
518 ● Unit 4: Array Processing and Table Handling
If there are not exactly seven records in TEMP-FILE, 600-ERR-RTN will be executed,
which terminates the job. The END-READ and END-IF scope terminators are valid with
COBOL 85; with older compilers omit the scope terminators and end the previous line
with a period.
01 POPULATION-ARRAY.
05 STATE OCCURS 50 TIMES.
10 COUNTY OCCURS 10 TIMES.
15 POPULATION PIC 9(10).
1. Assume there are 500 input records with the following format:
STATE COUNTY
NO NO POPULATION-IN
1 2 3 4 5 14
1 10 11 20 91 100
There are 50 such records, where the first record is for STATE 1, the second is for STATE 2,
and so on. Write a routine to load each record into the POPULATION-ARRAY.
3. Assume the input records have the following format:
STATE STATE
1 • • • 50
POP POP
1 10 491 500
There are 10 such records, where the first record is for COUNTY 1, the second is for COUNTY 2,
and so on. Write a routine to load each record into the POPULATION-ARRAY.
4. Suppose records were read with the format specified in Question 2 and we want to print a
report as follows:
STATE STATE-POP
1 Z,ZZZ,ZZZ,ZZZ
. .
. .
. .
50 Z,ZZZ,ZZZ,ZZZ
What type of array would we need in WORKING-STORAGE to print the 50 state population
totals?
5. Suppose records were read with the format specified in Question 3 and we want to print a
report as follows:
STATE--01
COUNTY POPULATION
1 Z,ZZZ,ZZZ,ZZZ
. .
. .
. .
10 Z,ZZZ,ZZZ,ZZZ
4. There would be no need to accumulate totals in an array at all. The 10 county population
figures for the first record would be added and printed as the STATE-POP for STATE 1. The
next record would be read and the procedure repeated for STATE 2.
5. Records are entered in such a way that all input would need to be stored before any state
totals could print. The POPULATION-ARRAY specified at the start of the Self-Test would be
used.
Example Assume that the following table has been loaded into storage:
01 INVENTORY-TABLE.
05 WAREHOUSE OCCURS 50 TIMES.
10 ITEM-X OCCURS 100 TIMES.
15 PART-NO PIC 9(4).
15 UNIT-PRICE PIC 999V99.
There are 50 warehouses, and each stores 100 items. Each warehouse stocks its own inventory,
which is different from the inventory at other warehouses. This means that a specific PART-NO
will appear only once in the table. There are 5000 table records, each with a warehouse number,
part number, and unit price. The first table record refers to warehouse 1, part number 1; the next
to warehouse 1, part number 2; the 101st to warehouse 2, part number 1, and so on.
Suppose that input transaction records have the following format:
1-4 PART-NO-IN
5-6 QTY-ORDERED
For each PART-NO-IN in a transaction record, we need to look up the corresponding PART-NO in
the table and find its UNIT-PRICE. We store the unit price for each part in the table and not in the
transaction record for the following reasons:
1. If each input transaction record contained a unit price, we would be keying unit price each
time a part was ordered. This would increase both keying costs and the risk of input errors.
2. Changes to unit prices can be more easily made to a relatively small number of table entries
than to a large number of input transaction records.
We store prices in an external table, which is in a file and is loaded in, rather than in an internal
table, which is established with VALUE clauses. External tables are used for this type of application
because the table elements themselves are likely to change with some frequency. That is, because
we anticipate that unit prices may change, we establish the INVENTORY-TABLE as an external table
that can be changed, when needed, by a separate program. If we defined it as an internal table
with VALUE clauses, we would need to modify and recompile our look-up program each time a
change to unit price occurred.
The output from this program will be a printed transaction report. Each time a PART-NO is
ordered, we will print the PART-NO and the TOTAL-AMT of the transaction, where TOTAL-AMT =
QTY-ORDERED (from the transaction record) 2 UNIT-PRICE (from the table). Since we will use a
SEARCH, the table we have described must include the appropriate INDEXED BY clauses with each
OCCURS level item:
Chapter 13: Multiple-Level Arrays and Tables ● 521
01 INVENTORY-TABLE.
05 WAREHOUSE OCCURS 50 TIMES INDEXED BY X1.
10 ITEM-X OCCURS 100 TIMES INDEXED BY X2.
15 PART-NO PIC 9(4).
15 UNIT-PRICE PIC 999V99.
The Identifier Used with the SEARCH Refers to the Lowest-Level OCCURS Entry
To SEARCH the table, we code SEARCH ITEM-X ... because ITEM-X is the lowest-level
OCCURS entry. Note that SEARCH ITEM-X increments the lowest-level index only. Hence if X1
is set to 1 initially, the SEARCH will perform a look-up on items in warehouse 1 only,
that is (1, 1) through (1, 100). To search all warehouses, the SEARCH itself must be exe-
cuted from a PERFORM ... VARYING that increments the major index, X1.
The routine would then appear as follows:
MOVE ’NO ’ TO MATCH-FOUND.
PERFORM 500-SEARCH-IT
VARYING X1 FROM 1 BY 1
UNTIL X1 > 50 OR MATCH-FOUND = ’YES’.
IF MATCH-FOUND = ’YES’
WRITE OUT-REC FROM TRANS-REC-OUT
AFTER ADVANCING 2 LINES
ELSE
PERFORM 600-NO-MATCH-ERR
END-IF.
.
.
.
500-SEARCH-IT.
SET X2 TO 1.
SEARCH ITEM-X kˆˆˆˆˆˆUse lowest-level OCCURS level here
WHEN PART-NO-IN = PART-NO (X1, X2)
MULTIPLY UNIT-PRICE (X1, X2) BY QTY-ORDERED
GIVING TOTAL-AMT
MOVE ’YES’ TO MATCH-FOUNDkˆˆEnables 500-SEARCH-IT to be
END-SEARCH. terminated properly when a
match is found
MATCH-FOUND is a field that is initialized at ’NO ’ and changed to ’YES’ only when
the corresponding PART-NO in the table is found. We terminate 500-SEARCH-IT when
a match is found (MATCH-FOUND = ’YES’) or the entire table has been searched (X1 >
50). 600-NO-MATCH-ERR would be executed only if no match existed between the PART-
NO-IN and a table entry.
The full program for this example appears in Figure 13.2.
Figure 13.2
IDENTIFICATION DIVISION.
Program to search a
PROGRAM-ID. FIG13-2.
double-level table. *
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INVENTORY-TABLE-IN ASSIGN TO DISK1.
SELECT TRANSACTION-FILE ASSIGN TO DISK2.
SELECT REPORT-OUT ASSIGN TO SYS$OUTPUT.
*
DATA DIVISION.
FILE SECTION.
FD INVENTORY-TABLE-IN
LABEL RECORDS ARE STANDARD.
01 INVENTORY-TABLE-REC.
05 T-WAREHOUSE-NO PIC 99.
05 T-PART-NO PIC 9999.
05 T-UNIT-PRICE PIC 999V99.
FD TRANSACTION-FILE
LABEL RECORDS ARE STANDARD.
01 TRANSACTION-REC.
05 PART-NO-IN PIC 9999.
05 QTY-ORDERED PIC 99.
522 ● Unit 4: Array Processing and Table Handling
Alternatively, we could use a PERFORM ... VARYING ... AFTER for searching the
table:
400-CALC-RTN.
MOVE PART-NO-IN TO PART-NO-OUT.
MOVE QTY-ORDERED TO QTY-OUT.
MOVE ’NO ’ TO MATCH-FOUND.
PERFORM
VARYING X1 FROM 1 BY 1
UNTIL X1 > 50 OR MATCH-FOUND = ’YES’
AFTER X2 FROM 1 BY 1
UNTIL X2 > 100 OR MATCH-FOUND = ’YES’
IF PART-NO-IN = PART-NO (X1, X2)
MULTIPLY UNIT-PRICE (X1, X2)
BY QTY-ORDERED
GIVING TOTAL-AMT
MOVE ’YES’ TO MATCH-FOUND
524 ● Unit 4: Array Processing and Table Handling
END-IF
END-PERFORM.
IF MATCH-FOUND = ’YES’
WRITE OUT-REC FROM TRANS-REC-OUT
AFTER ADVANCING 2 LINES
ELSE
PERFORM 600-NO-MATCH-ERR
END-IF.
READ TRANSACTION-FILE
AT END MOVE ’NO ’ TO ARE-THERE-MORE-RECORDS
END-READ.
Using the PERFORM ... VARYING ... AFTER, there is no need for the SEARCH in 500-
SEARCH-IT.
We SEARCH ITEM-X, not WAREHOUSE, because we are looking for an item within a
specific warehouse, warehouse 5 in this instance.
DEBUGGING TIP
If we code:
01 INVENTORY-TABLE.
05 WAREHOUSE OCCURS 50 TIMES INDEXED BY X1.
10 ITEM-X OCCURS 100 TIMES INDEXED BY X2.
15 PART-NO PIC 9(4).
15
. UNIT-PRICE PIC 999V99.
.
.
300-SEARCH.
SET X1, X2 TO 1.
SEARCH
. ITEM-X
.
.
the PART-NOs that will be searched are (1, 1) (1, 2) . . . (1, 100). The major-level
index, X1, will not be varied. If we want to SEARCH the entire table (all warehouses
and all items), we need to code:
PERFORM 300-SEARCH
VARYING X1 FROM 1 BY 1
. UNTIL X1 > 50.
.
.
300-SEARCH.
SET X2 TO 1.
SEARCH
. ITEM-X
.
.
Chapter 13: Multiple-Level Arrays and Tables ● 525
If we code:
SET X1, X2 TO 1.
SEARCH .
WAREHOUSE
.
.
the PART-NOs searched will be (1, 1) (2, 1) . . . (50, 1). That is, only the major-level
index, X1, will be varied, not the minor index, X2.
To search an entire array such as the preceding, we use a PERFORM ... VARYING,
which varies the major index and where the module being performed includes a
SEARCH:
PERFORM VARYING X1
FROM 1 BY 1 UNTIL X1 > 50
SET X2 TO 1
SEARCH DISTRICT
.
.
.
END-PERFORM
H
WHEN POPULATION (X1, X2) = 123000
SET is used in place of SET X1-OUT TO X1
MOVE to transmit X1 and
X2 to an output area SET X2-OUT TO X2
526 ● Unit 4: Array Processing and Table Handling
Suppose we wish to find the total number of districts in STATE 3 with populations
less than 50,000. In this case, we want to keep the STATE index, X1, fixed at 3. To do
this, we could code the following:
MOVE ZERO TO CTR2.
SET X1 TO 3.
PERFORM 300-SEARCH-RTN
Chapter 13: Multiple-Level Arrays and Tables ● 527
DEBUGGING TIP
When an array or a table is to be searched for one specific entry or match, use
the SEARCH verb. This is because the SEARCH instruction stops as soon as the con-
dition tested in the WHEN clause is met. You could, however, use a PERFORM with
an IF instead of a SEARCH. When a table or an array is being searched where there
may be more than one ‘‘hit’’ or match to be tabulated or counted, it is better to
use PERFORMs and an IF instead of the SEARCH. With multiple-level arrays or tables,
use a PERFORM ... VARYING ... AFTER with an IF test to check for multiple
matches.
We have seen that OCCURS clauses may be written on one or two levels. We may also
use triple-level OCCURS clauses. A maximum of seven levels of OCCURS clauses may be
used with COBOL 85, but COBOL 74 permits only up to three levels.
Suppose we have a table consisting of 50 state populations. Each state is further
subdivided into 10 counties. Each county has precisely five district figures. The follow-
ing array may be coded in the WORKING-STORAGE SECTION:
01 POPULATION-TABLE.
05 STATE OCCURS 50 TIMES.
10 COUNTY OCCURS 10 TIMES.
15 DISTRICT-POP OCCURS 5 TIMES PIC 9(10).
In this way, we have defined 2500 fields (50 2 10 2 5) in storage, each 10 positions
long. To access any field defined by several OCCURS clauses, we use the lowest-level data-
name. In this illustration, the data-name DISTRICT-POP must be used to access any of
the 2500 fields of data.
Since DISTRICT-POP is defined by a triple-level OCCURS clause, three subscripts are
used to access the specific field desired. The first subscript refers to the major-level item,
STATE. The second subscript refers to the intermediate-level item, COUNTY. The third sub-
script refers to the minor-level item, DISTRICT-POP. Subscripts are always enclosed
within parentheses. Each subscript is separated from the next by a comma and a space.
If we code DISTRICT-POP (5, 4, 3), the DISTRICT-POP specified refers to the popu-
lation figure for STATE 5, COUNTY 4, DISTRICT 3. An item defined by a triple-level
OCCURS clause is accessed with three subscripts.
Example 1 Write a routine to find the smallest figure in the POPULATION-TABLE array. (We assume that data
has already been placed in the array.) Store this smallest figure in HELD.
Using nested PERFORM ... VARYING statements to achieve this looping, we have:
MOVE DISTRICT-POP (1, 1, 1) TO HELD.
PERFORM 200-RTN-1
VARYING SUB1 FROM 1 BY 1 UNTIL SUB1 > 50.
PERFORM 500-NEXT-RTN.
PERFORM 600-EOJ-RTN.
200-RTN-1.
PERFORM 300-RTN-2
VARYING SUB2 FROM 1 BY 1 UNTIL SUB2 > 10.
300-RTN-2.
528 ● Unit 4: Array Processing and Table Handling
PERFORM 400-RTN-3
VARYING SUB3 FROM 1 BY 1 UNTIL SUB3 > 5.
400-RTN-3.
IF DISTRICT-POP (SUB1, SUB2, SUB3) < HELD
MOVE DISTRICT-POP (SUB1, SUB2, SUB3) TO HELD
END-IF.
Using a PERFORM ... VARYING ... AFTER in the first PERFORM, we can eliminate 200-RTN-1
and 300-RTN-2:
PERFORM 400-RTN-3
VARYING SUB1 FROM 1 BY 1 UNTIL SUB1 > 50
AFTER SUB2 FROM 1 BY 1 UNTIL SUB2 > 10
AFTER SUB3 FROM 1 BY 1 UNTIL SUB3 > 5.
Note that more than one AFTER clause can be used in a PERFORM ... VARYING, with
the last one being performed first. That is, the minor subscript is varied first.
With COBOL 85, we can use nested in-line PERFORMs:
MOVE DISTRICT-POP (1, 1, 1) TO HELD.
PERFORM VARYING SUB1 FROM 1 BY 1
UNTIL SUB1 > 50
PERFORM VARYING SUB2 FROM 1 BY 1
UNTIL SUB2 > 10
PERFORM VARYING SUB3 FROM 1 BY 1
UNTIL SUB3 > 5
IF DISTRICT-POP (SUB1, SUB2, SUB3) < HELD
MOVE DISTRICT-POP (SUB1, SUB2, SUB3)
TO HELD
END-IF
END-PERFORM
END-PERFORM
END-PERFORM.
PERFORM 500-NEXT-RTN.
PERFORM 600-EOJ-RTN.
or
MOVE DISTRICT-POP (1, 1, 1) TO HELD.
PERFORM VARYING SUB1 FROM 1 BY 1
UNTIL SUB1 > 50
AFTER SUB2 FROM 1 BY 1 UNTIL SUB2 > 10
AFTER SUB3 FROM 1 BY 1 UNTIL SUB3 > 5
IF DISTRICT-POP (SUB1, SUB2, SUB3) < HELD
MOVE DISTRICT-POP (SUB1, SUB2, SUB3)
TO HELD
END-IF
END-PERFORM.
PERFORM 500-NEXT-RTN.
PERFORM 600-EOJ-RTN.
Example 2 Suppose we want to store the hourly temperatures for Los Angeles or any other city for the years
1993 –1995. We could establish a triple-level or three-dimensional array as follows:
01 TEMPERATURE-ARRAY.
05 YEAR-X OCCURS 3 TIMES.
10 DAY-X OCCURS 365 TIMES.
15 HOURLY-TEMP OCCURS 24 TIMES PIC S9(3).
Note that a PIC of S9(3) allows for temperatures from 1999 to 999.
To display the temperature at 3 A.M. on January 2, 1993, we have: DISPLAY HOURLY-TEMP (1,
2, 3). The number 1 refers to the first year specified, 1993; 2 refers to the second day of that year
and 3 refers to the third hour, or 3 A.M.
To load the array, we could read 1095 (3 years 2 365 days) records each with 24 hourly
temperatures:
PERFORM 400-LOAD-IT VARYING SUB1 FROM 1 BY 1 UNTIL SUB1 > 3
AFTER SUB2 FROM 1 BY 1 UNTIL SUB2 > 365.
Chapter 13: Multiple-Level Arrays and Tables ● 529
.
.
.
400-LOAD-IT.
READ DAY-TEMP-FILE
AT END MOVE ’NO ’ TO MORE-RECS
END-READ.
PERFORM 500-STORE-24-VALUES
VARYING SUB3 FROM 1 BY 1 UNTIL SUB3 > 24.
500-STORE-24-VALUES.
MOVE IN-TEMP (SUB3) TO HOURLY-TEMP (SUB1, SUB2, SUB3).
To determine the average temperature for 1994 we could code in-line PERFORMs with COBOL
85 as follows:
MOVE 0 TO TOTAL.
MOVE 2 TO SUB1.
PERFORM VARYING SUB2 FROM 1 BY 1 UNTIL SUB2 > 365
PERFORM VARYING SUB3 FROM 1 BY 1 UNTIL SUB3 > 24
ADD HOURLY-TEMP (SUB1, SUB2, SUB3) TO TOTAL
END-PERFORM
END-PERFORM.
COMPUTE AVERAGE = TOTAL / 8760.
DISPLAY ’THE AVERAGE TEMPERATURE FOR 1994 IS ’, AVERAGE.
Note that there are no periods between the first PERFORM and the last END-PERFORM. We divide
TOTAL by 8760, which is 365 days 2 24 hours.
To find the average temperature for January 3 for the three years 1993 –1995 we could code:
MOVE 0 TO TOTAL.
MOVE 3 TO SUB2.
PERFORM 200-MAJOR-RTN VARYING SUB1 FROM 1 BY 1
UNTIL SUB1 > 3.
COMPUTE AVERAGE = TOTAL / 72
DISPLAY ’THE AVERAGE TEMPERATURE FOR JAN 3 FOR 1993 –1995 IS ’,
AVERAGE.
200-MAJOR-RTN.
PERFORM 300-MINOR-RTN VARYING SUB3 FROM 1 BY 1
UNTIL SUB3 > 24.
300-MINOR-RTN.
ADD HOURLY-TEMP (SUB1, SUB2, SUB3) TO TOTAL.
A PERFORM ... VARYING ... AFTER could be used instead. With COBOL 85, we could code
an in-line PERFORM ... VARYING ... AFTER as follows:
MOVE 0 TO TOTAL.
MOVE 3 TO SUB2.
PERFORM VARYING SUB1 FROM 1 BY 1
UNTIL SUB1 > 3
AFTER SUB3 FROM 1 BY 1
UNTIL SUB3 > 24
ADD HOURLY-TEMP (SUB1, SUB2, SUB3) TO TOTAL
END-PERFORM.
COMPUTE AVERAGE = TOTAL / 72.
DISPLAY ’THE AVERAGE TEMPERATURE FOR JAN 3 FOR 1993–1995 IS ’,
AVERAGE.
Because seven levels of OCCURS are permitted with COBOL 85, a maximum of six
AFTER clauses are therefore allowed with COBOL 85. The limit for the number of AFTER
clauses with COBOL 74 is two.
4. The identifier used with the SEARCH statement should typically be the one on the lowest
OCCURS level. Only the index on the same level as the OCCURS level will be incremented
by the SEARCH. That is, SEARCH XXX, for example, will only vary the index specified with
XXX. Consider the following:
X2 is the only index incremented in the search regardless of whether XXX is subordinate
to an OCCURS or contains another level of OCCURS.
B. COBOL 85 permits seven levels of OCCURS; COBOL 74 permits three levels.
CHAPTER SELF-TEST 1. With MOVE ITEMX (SUB1, SUB2) TO HELD, SUB1 refers to the -level OCCURS clause
and SUB2 refers to the -level OCCURS clause.
2. Consider the following DATA DIVISION entry:
01 ARRAY1.
05 FIELDX OCCURS 20 TIMES.
10 FIELDXX OCCURS 50 TIMES.
15 ITEMX PICTURE S99.
The number of storage positions reserved for this area is . The data-name that
may be used to access a field in the PROCEDURE DIVISION is . If ITEMX (CTRA,
CTRB) is used in the PROCEDURE DIVISION, then CTRA may vary from to
and CTRB may vary from to .
3. If three subscripts are used to access an item, the first refers to the level, the second
to the level, and the third to the level.
4. Each subscript within the parentheses is separated from the next by a followed
by a .
5. If a SEARCH is used for accessing a double-level table, a(n) clause must be used
on both OCCURS levels.
Assume the following triple-level array has been loaded for Questions 6 –10:
01 INVENTORY-DATA.
05 WAREHOUSE OCCURS 5 TIMES.
10 PRODUCT-NO OCCURS 20 TIMES.
15 PRODUCT-SUPPLIER OCCURS 5 TIMES PIC X(10).
PRACTICE Write a program to print two sales reports. The first report prints seven daily totals, edited. The
PROGRAM second report prints 25 salesperson totals, edited. The problem definition is shown in Figure 13.3.
Notes:
a. For the first report, each daily total represents the sum of all 25 salesperson sales totals for
the corresponding day. For the second report, each salesperson total represents the sum of
the seven daily sales totals for the corresponding salesperson.
b. Records are not in sequence.
The pseudocode, hierarchy chart, program, and sample input and output are in Figure 13.4.
SALESPERSON-REPORT
SALES-FILE Record Layout
$ ¢
1 2 3 5 6 10 11 25
T 18 S UN $Z ZZ , ZZ Z , ZZZ . 9 9
19
Figure 13.3
(continued)
ZERO-TABLE
Initialize the array
HEADING-RTN-1
Add 1 to Page Counter
Print the Headings for the Daily Report
HEADING-RTN-2
Add 1 to Page Counter
Print the Headings for the Salesperson Number Report
CALC-RTN
Add the input amount to the appropriate array entry
Read a record
WRITE-RTN-1
Initialize the total area
PERFORM Add-Rtn 25 Times
Print the day and the daily total
Chapter 13: Multiple-Level Arrays and Tables ● 533
ADD-RTN
Add appropriate array entry to total
Hierarchy Chart
100-MAIN-
MODULE
800-ADD- 800-ADD-
RTN RTN
IDENTIFICATION DIVISION.
PROGRAM-ID. SAMPLE.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SALES-FILE ASSIGN TO CH13DAT.
SELECT PRINT-FILE ASSIGN TO SYS$OUTPUT.
DATA DIVISION.
FILE SECTION.
FD SALES-FILE
LABEL RECORDS ARE STANDARD
RECORD CONTAINS 25 CHARACTERS.
01 IN-REC.
05 DAY-IN PIC 99.
05 SLS-NUM-IN PIC 999.
05 AMOUNT-IN PIC 9(3)V99.
05 PIC X(15).
FD PRINT-FILE
LABEL RECORDS ARE OMITTED.
01 PRINT-REC PIC X(132).
WORKING-STORAGE SECTION.
01 ARE-THERE-MORE-RECORDS PIC XXX VALUE ’YES’.
88 NO-MORE-RECORDS VALUE ’NO ’.
01 WS-PAGE PIC 99 VALUE ZERO.
01 WS-DATE.
05 WS-YEAR PIC 99.
05 WS-MONTH PIC 99.
05 WS-DAY PIC 99.
01 WS-TOT-SALES PIC 9(9)V99 VALUE ZERO.
01 WS-CTR1 PIC 99 VALUE ZERO.
01 WS-CTR2 PIC 99 VALUE ZERO.
01 WS-TABLE1.
05 SLS-LEVEL OCCURS 25 TIMES.
10 AMOUNT-T OCCURS 7 TIMES PIC 9(5)V99.
534 ● Unit 4: Array Processing and Table Handling
Sample Input
6 6 6
02 022 10000 02 005 30000 02 023 45000
03 024 25000 07 003 04500 05 008 22000
03 021 30000 06 001 30000 01 008 23000
01 005 40000 04 002 12000 03 017 60000
01 005 10000 05 004 14500 02 011 22000
Records Records Records
01 003 25000 02 005 13500 03 009 43000
1–11 12–22 23–32
05 004 12000 06 003 12500 05 015 50000
04 003 13000 01 019 80000 03 008 34000
05 003 12000 05 016 23000 02 006 23000
02 007 11000 01 018 90000 03 002 10000
06 005 60000 02 014 55500
DAILY FIGURES
MON $ 2,680.00
TUE $ 2,100.00
WED $ 2,020.00
THU $ 250.00
FRI $ 1,335.00
SAT $ 1,025.00
SUN $ 45.00
Sample Output
Report of total sales for
each salesperson SALESPERSON REPORT PAGE 1 01/11/94
1 $ 300.00
2 $ 220.00
3 $ 670.00
4 $ 265.00
5 $ 1,535.00
6 $ 230.00
Chapter 13: Multiple-Level Arrays and Tables ● 537
9 $ 430.00
10 $ 0.00
11 $ 220.00
12 $ 0.00
13 $ 0.00
14 $ 555.00
15 $ 500.00
16 $ 230.00
17 $ 600.00
18 $ 900.00
19 $ 800.00
20 $ 0.00
21 $ 300.00
22 $ 100.00
23 $ 450.00
24 $ 250.00
25 $ 0.00
REVIEW QUESTIONS
I. True-False 1. If an item is defined with a double-level OCCURS clause, the first subscript refers to the lower-
Questions level OCCURS.
2. Triple-level subscripting is the maximum for COBOL 85.
3. Subscripts and indexes must always be numeric.
4. The following entries define 5000 positions of storage:
01 TABLE-1.
05 ITEM-1 OCCURS 50 TIMES.
10 ITEM-2 OCCURS 10 TIMES PIC S9(10).
II. General Questions 1. There are 50 classes in College X. Each class has exactly 40 students. Each student has taken
six exams. Write a double-level OCCURS clause to define an area of storage that will hold these
scores.
2. Write a triple-level OCCURS clause for Question 1.
3. Write the file and record description entries for a file of input records that will contain
students’ test scores as described above. Each student record will contain six scores in the
first 18 positions. The first record is for the first student in class 1, . . . the 40th record is for
the 40th student in class 1, the 41st record is for the first student in class 2, and so on.
4. Using the solutions to Questions 2 and 3, write the PROCEDURE DIVISION routines to read
the exam records and to accumulate the data in the array.
5. Write a routine to find the class with the highest class average.
6. Write a routine to find the student with the highest average.
7. Write a routine to find the student with the highest grade for Exam 2. Print the student name
and class number and the grade.
8. Print the number of students in class 5 with a grade on Exam 3 that was less than 65.
9. Write a routine using the PERFORM ... VARYING ... AFTER to give each student three extra
points as a curve.
10. Suppose a company has four health insurance plans with 3 options for each.
Health Plan 1
(basic) $510 $ 640 $1125
Health Plan 2
(major medical) 635 825 900
Health Plan 3
(comprehensive) 715 905 1300
Health Plan 4
(including dental) 975 1100 1725
The cost of each plan is apt to vary so we store the costs in an external table.
a. Write the WORKING-STORAGE entries for the table.
b. Write a routine to find the cheapest plan for each option.
III. Validating Data Modify the Practice Program so that it includes coding to (1) test for all errors and (2) print a
control listing of totals (records processed, errors encountered, batch totals).
PERFORM 200-TABLE-ENTRY
VARYING X1 FROM 1 BY 1 UNTIL X1 > 5.
READ TRANS-FILE
AT END MOVE ’NO ’ TO MORE-TRANS-RECS
END-READ.
PERFORM 400-CALC-RTN UNTIL NO-MORE-TRANS-RECS.
CLOSE TABLE-FILE
TRANS-FILE
PRINT-FILE.
STOP RUN.
200-TABLE-ENTRY.
PERFORM 300-ENTER-IT
VARYING X2 FROM 1 BY 1 UNTIL X2 > 150.
300-ENTER-IT.
MOVE T-ITEM-NO TO ITEM-NO (X2, X1).
MOVE T-QTY-ON-HAND TO PRICE (X2, X1).
400-CALC-RTN.
MOVE ACCT-NO TO ACCT-OUT.
MOVE ACCT-NAME TO NAME-OUT.
MOVE 0 TO FOUND-IT.
PERFORM 500-SEARCH-TABLE
VARYING X1 FROM 1 BY 1
UNTIL X1 > 5 OR FOUND-IT = 1.
WRITE PRINT-REC FROM DETAIL-REC
AFTER ADVANCING 2 LINES.
READ TRANS-FILE
AT END MOVE ’NO ’ TO MORE-TRANS-RECS
END-READ.
500-SEARCH-TABLE.
SET X2 TO 1.
SEARCH STOCK-ITEMS
WHEN ITEM-IN = ITEM-NO (X1, X2)
MULTIPLY QTY-IN BY PRICE
GIVING GROSS-OUT
MOVE 1 TO FOUND-IT
END-SEARCH.
1. Two syntax errors occur on the lines associated with the SET and the SEARCH. Both errors are
the result of an omission within TABLE-1. Find and correct the error(s).
2. A program interrupt occurs during execution of 300-ENTER-IT. Determine why and fix the
error.
3. Suppose two warehouses have the same ITEM-NO (e.g., 127). How will this affect processing?
Would this processing be correct? If not, explain how you would modify the program.
4. Suppose the company has decided to increase the price of each item by 10% but has not yet
made the appropriate changes to the table entries. Make the necessary changes to 400-CALC-
RTN so that GROSS-OUT is correct.
5. There is another way to make the 10% price increases. You can make them to the table entries
as the table is entered. Recode the table-entry routine so that prices are increased by 10%.
Which method is more efficient?
PROGRAMMING 1. Write a program to tabulate the number of employees by area within department. The problem
ASSIGNMENTS definition appears in Figure 13.5.
Notes:
a. There are 10 areas within each department; there are 20 departments. Add 1 to a corres-
ponding total for each employee record read.
b. Records are not in sequence.
c. All totals should be edited to suppress high-order zeros.
540 ● Unit 4: Array Processing and Table Handling
PRINT-FILE 1 2 3 4 5 80
T 26 D E P ARTMEN T - 99 ZZ9 ZZ9 ZZ9 ZZ9 ZZ9 ZZ9 ZZ9 ZZ9 ZZ9 ZZ9
27
Figure 13.5
Problem definition
for Programming
Assignment 1. 2. Write a program to tabulate the number of employees by office within territory. The problem
definition is shown in Figure 13.6. There is one input record for each employee.
Notes:
a. There are two offices within each territory; there are three territories.
b. Records are not in sequence.
3. For Pass-Em State College, read in student records with the following format:
1 9 10 30 31 32 33 35 36 38
1 = Freshman
2 = Sophomore 1 = Business
3 = Junior 2 = Liberal Arts
4 = Senior 3 = Engineering
Assume the records are not in sequence. Set up a two-dimensional (3 2 4) array that will store
the total number of students in each class within each school and their accumulated GPAs.
After all records have been read and processed, print the average GPA per class in each school.
The array should be established as follows:
01 ARRAY-1.
05 SCHOOL OCCURS 3 TIMES.
10 CLASSES OCCURS 4 TIMES.
15 TOT-STUDENTS PIC 9(3).
15 ACCUM-GPA PIC 999V99.
Chapter 13: Multiple-Level Arrays and Tables ● 541
For each class within each school divide ACCUM-GPA by total number of students to get an
average GPA:
SCHOOL
4. Redo the Practice Program in this chapter assuming the 25 salespeople have unique salesper-
son numbers that can be anything from 001 to 999.
5. Interactive Processing. A store has five distribution centers that are numbered 1–5. Each
distribution center sets its own prices for each of the 500 parts it stores, numbered 1–500. Write
a program to load in as an external table unit prices for each of the 500 parts stored by each
of the five distribution centers. Then, write an interactive module that enables a user to key
in a requested distribution center and part number, and have the computer display the unit
price for the requested part at the requested distribution center. Use appropriate prompts and
error control procedures.
Figure 13.6
Problem definition
for Programming
Assignment 2.
Systems Flowchart
PAYROLL-MASTER
80-position records CH 13-2
standard labels PROGRAM
20 records/block
EMPLOYEE-REPORT
JOB
EMPLOYEE EMPLOYEE TERRITORY OFFICE CLASSIFI-
NO. NAME NO. NO. CATION
CODE
1 5 6 25 26 27 28 29 30 46 47 48 49 80