Chapter 15. SINGLE-LEVEL ARRAYS AND TABLES

CHAPTER OBJECTIVES

Upon completion of this chapter, you should be able to

  • Establish a series of items using an OCCURS clause.

  • Access and manipulate data stored in an array or table.

  • Explain the rules for using an OCCURS clause in the DATA DIVISION.

  • Explain and demonstrate how an index or subscript is used with an array.

  • Demonstrate the use of a SEARCH and SEARCH ALL for a table look-up.

AN INTRODUCTION TO SINGLE-LEVEL OCCURS CLAUSES

WHY OCCURS CLAUSES ARE USED

We use an OCCURS clause to indicate the repeated occurrence of fields with the same format. Some of the uses of an OCCURS clause include:

  1. Defining a series of input or output fields, each with the same format.

  2. Defining a series of totals in WORKING-STORAGE to which amounts are added. After all data is accumulated, the totals can be printed.

  3. Defining a table in WORKING-STORAGE to be accessed by each input record. With a table, we use the contents of some input field to "look up" the required data in the table.

DEFINING FIELDS WITH AN OCCURS CLAUSE

Suppose we have one 72-character input record that consists of 24 hourly temperature fields. Each field is three positions long and indicates the temperature for a given city at a particular hour. Using traditional methods, defining the input record with 24 independent hourly fields would prove cumbersome:

DEFINING FIELDS WITH AN OCCURS CLAUSE

We use the S in the PIC clause for cities in which the temperature might fall below zero.

Moreover, to obtain an average daily temperature would also require a great deal of coding:

COMPUTE AVERAGE-TEMPERATURE = (ONE-AM + TWO-AM + . . . + MIDNIGHT)/24.

The dots (. . .) mean that the software developer would need to specify all 24 entries.

The 24 temperature fields have exactly the same format, that is, they are numeric fields containing three integer positions and no decimals. Since the format or PIC clause for each of the 24 fields is identical, we could use an OCCURS clause to define the fields. We call the entire 72-position area an array that is divided into 24 three-position fields.

With an OCCURS clause, we specify the number of items being defined in the array and the PIC clause of each:

DEFINING FIELDS WITH AN OCCURS CLAUSE

The OCCURS clause, then, defines 24 three-position numeric fields with no decimals. Thus, TEMPERATURE is an array that refers to 72 positions or bytes of storage, or 24 three-byte fields. (See Figure 15.1 for an illustration.)

Storing 24 three-position numeric fields (temperatures) in an array.

Figure 15.1. Storing 24 three-position numeric fields (temperatures) in an array.

Defining a Subscript. Collectively, these 24 fields within the array are called TEMPERATURE, which is the identifier used to access them in the PROCEDURE DIVISION. We would use the identifier TEMPERATURE along with a subscript that indicates which of the 24 fields we wish to access. To refer to an item defined by an OCCURS clause, we specify the identifier, TEMPERATURE in our example, followed by the subscript in parentheses. The subscript indicates the specific TEMPERATURE desired. Thus, to print the 2 A.M. temperature, we write

Storing 24 three-position numeric fields (temperatures) in an array.

The relationship between OCCURS clauses and subscripts is

  1. An OCCURS clause is defined in the DATA DIVISION to indicate the repeated occurrence of items with the same format in an array.

  2. A subscript is used in the PROCEDURE DIVISION to indicate which specific element within the array is to be accessed.

We use a subscript, along with the identifier that is defined with an OCCURS clause, to refer to an item within an array. In the preceding example, the subscript can have any value from 1 through 24. The following, however, have invalid subscripts.

Invalid Subscripts

Storing 24 three-position numeric fields (temperatures) in an array.

Since there is no zero element or twenty-fifth element in the array, these two MOVE statements are trying to access elements that are outside the limits of the array. The subscript cannot take on the values 0 or 25; only the integer values 1 through 24 are valid.

Coding Rules for Subscripts. The coding of a subscript in the PROCEDURE DIVISION requires precise spacing. There must be at least one space between the identifier and the left parenthesis that precedes the subscript. Similarly, the subscript must be enclosed in parentheses with no spaces within the parentheses.

The following might result in syntax errors unless the compiler has enhancements that permit more flexible spacing:

Storing 24 three-position numeric fields (temperatures) in an array.

A Subscript May Be an Integer or an Identifier. Thus far, we have considered subscripts that are numeric literals. A subscript, however, may also be a data-name with a numeric PICTURE clause. Suppose SUB, an abbreviation for subscript, were defined in the WORKING-STORAGE section as follows:

Storing 24 three-position numeric fields (temperatures) in an array.

We could move the tenth element of the TEMPERATURE array to TEMPERATURE-OUT:

Storing 24 three-position numeric fields (temperatures) in an array.

Subscripts, then, identify items defined with OCCURS clauses and can be either integers or data-names. If a data-name is used as a subscript, it must have a numeric PICTURE clause and an integer value. Using a data-name as a subscript enables us to vary the contents of the subscript, so that we can process a series of items with a single routine.

To determine the average daily temperature we write a routine that adds one temperature at a time to a total. The PERFORM . . . VARYING statement is one option for accessing subscripted entries since it initializes, increments, and tests the subscript used in the procedure. The PERFORM . . . VARYING statement varies

the contents of a subscript called SUB from 1 to 24, so that all 24 temperatures are added. The subscript field SUB is defined as a WORKING-STORAGE entry with PIC 9(2). Following is the program excerpt for this problem.

With a PERFORM . . . VARYING

Storing 24 three-position numeric fields (temperatures) in an array.

The PERFORM . . . VARYING statement (1) initializes SUB at 1, (2) adds each TEMPERATURE within the array, and (3) increments SUB until it has processed all 24 temperatures:

Alternatively, the PERFORM . . . TIMES statement could be used.

With a PERFORM . . . TIMES

Storing 24 three-position numeric fields (temperatures) in an array.

Also, the in-line PERFORM may be used with the PERFORM . . . VARYING, PERFORM . . . TIMES, or PERFORM . . . UNTIL statements, as shown in the PERFORM . . . UNTIL below.

With an In-line PERFORM . . . UNTIL

Storing 24 three-position numeric fields (temperatures) in an array.

When using the UNTIL or TIMES option of the PERFORM, the subscript must be initialized prior to the PERFORM; it must also be incremented within the routine or loop to be performed.

RELATIVE SUBSCRIPTING

As illustrated, a subscript can be either (1) a data-name with numeric, integer value or (2) a numeric literal with integer value. A subscript can also have a relative value, that is, a data-name or integer from which, or to which, another data-name or integer is subtracted or added. We call this a relative subscript. Thus, the following is acceptable:

RELATIVE SUBSCRIPTING

Tip

DEBUGGING TIP

Be sure the PIC clause of the subscript includes enough 9s to hold all possible values for the subscript. If a subscript used with an array containing 100 elements has PIC 9(2) rather than 9(3), a processing error will occur when the program tries to access the 100th element in the array. Also, ensure that the content of the subscript is always greater than or equal to 1 and less than or equal to the maximum number of elements in the array.

USING AN OCCURS CLAUSE IN WORKING-STORAGE

Thus far, we have seen that an OCCURS clause may be used as part of an input record to indicate the repeated occurrence of incoming fields. Similarly, an OCCURS clause may be used as part of an output record to define a series of fields. An OCCURS clause may be used to define fields either in the FILE SECTION or in WORKING-STORAGE.

Suppose, for example, that an input file contains transaction records:

USING AN OCCURS CLAUSE IN WORKING-STORAGE

Since there is no item that is repeated, we do not need to use the OCCURS clause within this input record. Suppose we wish to establish an array in WORKING-STORAGE that consists of 12 monthly totals for all transaction records.

USING AN OCCURS CLAUSE IN WORKING-STORAGE

We define 12 MONTH-TOTAL fields in WORKING-STORAGE to store the total of all transaction amounts for months 01–12, respectively. Each MONTHLY-TRANSACTION-RECORD read will include an AMOUNT-IN and a MONTH-IN number. The program adds the AMOUNT-IN to a MONTH-TOTAL field determined by the content of the MONTH-IN entered within DATE-OF-TRANSACTION-IN. If MONTH-IN = 2, for example, the program adds the AMOUNT-IN to the second MONTH-TOTAL, or MONTH-TOTAL (2).

Note that the MONTH-TOTAL fields must be initialized to zero at the beginning of the program before any AMOUNT-IN fields are added to them. If not, a decimal data error will occur when the program tries to add the AMOUNT-IN field to one of the MONTH-TOTAL elements in the array. There are several methods that can be used to initialize the 12 MONTH-TOTAL fields.

To initialize the 12 MONTH-TOTAL fields to zeros in the PROCEDURE-DIVISION, the following may be used:

USING AN OCCURS CLAUSE IN WORKING-STORAGE

The VALUE clause may be used in WORKING-STORAGE:

USING AN OCCURS CLAUSE IN WORKING-STORAGE

The following program excerpt illustrates how the total amounts for months 1–12 are accumulated.

USING AN OCCURS CLAUSE IN WORKING-STORAGE

A subscript called MONTH-IN determines to which MONTH-TOTAL element the content of the input field AMOUNT-IN is to be added. In this case, this subscript is also an input field. As noted previously, subscripts can be data-names defined in either the FILE SECTION or the WORKING-STORAGE SECTION. If MONTH-IN is 3, for example, the program adds AMOUNT-IN to the third MONTH-TOTAL element. Coding ADD AMOUNT-IN TO MONTH-TOTAL (MONTH-IN) will add an amount to the month total element indicated by the month number entered as input.

USING LIKE CLAUSE WITH OCCURS CLAUSE

The LIKE clause may be used within an OCCURS clause to define an element of the array as having the same attributes as a field outside the array. Consider the following example.

USING LIKE CLAUSE WITH OCCURS CLAUSE

In this example, MONTH-TOTAL, which occurs 12 times, is defined using the LIKE clause. The MONTH-TOTAL field is defined as LIKE AMOUNT-IN, that is, it takes on the same attributes as AMOUNT-IN. In addition, the use of (+2) makes the length of the field two digits longer. The array MONTHLY-TOTAL-ARRAY is 84 bytes long.

Let us consider another example where the LIKE clause is used to define a field that will take on the same attributes as a field within an array.

USING LIKE CLAUSE WITH OCCURS CLAUSE

In this example, MONTH-OUT takes on the same attributes as MONTH-NAME in the MONTHLY-NAME-ARRAY. Thus, MONTH-OUT is defined as PIC X(9). The MONTH-TOTAL-RECORD is 13 bytes long.

VALIDATING INPUT DATA

You should use input fields as subscripts only if you are sure they have valid values. In this case, MONTH-IN should only vary from 1 to 12. If MONTH-IN were erroneously entered with a value that was less than 01 or greater than 12, the program will terminate abnormally. To minimize such errors, 200-PROCESS-RECORD-RTN could include a validity check:

VALIDATING INPUT DATA

From the program excerpt you can see that the module will read each record and, if it contains a valid MONTH-IN, the AMOUNT-IN will be added to the appropriate MONTH-TOTAL element. After all the input has been processed, control will return to the main module where the monthly totals are printed. The

monthly totals are to print in sequence from 1 to 12. The pseudocode for this entire program is shown in Figure 15.2. The program that uses a PERFORM 300-PRINT-RTN VARYING . . . statement, with a subscript varying from 1 to 12, to print the array is shown in Figure 15.3.

Pseudocode for program that accumulates and prints 12 month totals.

Figure 15.2. Pseudocode for program that accumulates and prints 12 month totals.

Thus, the WORKING-STORAGE array called MONTHLY-TOTAL-ARRAY is accessed in two ways:

  1. Using MONTH-IN as a subscript: for each record read, the input field called MONTH-IN is used to specify to which MONTH-TOTAL element the AMOUNT-IN is to be added. Data need not be entered in any specific sequence; the content of MONTH-IN determines which MONTH-TOTAL element is used in the addition.

  2. Using a subscript called SUB defined in WORKING-STORAGE: after all input has been read and processed, a subscript called SUB is varied from 1 to 12 to print out the contents of the MONTH-TOTALs in consecutive order.

Note that a control break procedure could be used in place of array processing if the data were entered in sequence by month number.

Program that accumulates and prints 12 monthly totals.

Figure 15.3. Program that accumulates and prints 12 monthly totals.

RULES FOR USE OF THE OCCURS CLAUSE

LEVELS 02–49

The OCCURS clause is used on levels 02–49 where fields are defined. That is, the OCCURS clause is not valid for the 01 level since the 01 level is used for defining records.

DEFINING ELEMENTARY OR GROUP ITEMS WITH AN OCCURS CLAUSE

Thus far, we have focused on OCCURS clauses that define elementary items.

DEFINING ELEMENTARY OR GROUP ITEMS WITH AN OCCURS CLAUSE

The 05-level item defined by an OCCURS clause has a PIC clause, making the 12 MONTH-TOTAL fields elementary items. Thus, MONTHLY-TOTAL-ARRAY is an 84-byte array (12 × 7) consisting of 12 elementary items:

DEFINING ELEMENTARY OR GROUP ITEMS WITH AN OCCURS CLAUSE

The identifier used with an OCCURS clause may be a group item as well.

DEFINING ELEMENTARY OR GROUP ITEMS WITH AN OCCURS CLAUSE

In this instance, CITY and TAX-RATE each occur 20 times within a group item called CITY-TAX:

DEFINING ELEMENTARY OR GROUP ITEMS WITH AN OCCURS CLAUSE

Similarly, to print out 20 tax rates, we could have the following print record:

DEFINING ELEMENTARY OR GROUP ITEMS WITH AN OCCURS CLAUSE

We want the decimal point to print, so we use .999 as the PIC clause for TAX-RATE-OUT. The blank field name that occurs 20 times will ensure that there are two spaces between each printed tax rate.

ACCESSING WORKING-STORAGE AREAS DEFINED BY AN OCCURS CLAUSE

Example 1: Consider again the array consisting of monthly totals that was defined previously.

ACCESSING WORKING-STORAGE AREAS DEFINED BY AN OCCURS CLAUSE

Suppose all the data has been read from the transaction records and added to the correct array element. Now we wish to write a routine to find the year-end final total, that is, the sum of all monthly totals. The structured pseudocode for this procedure is

Structured Pseudocode

ACCESSING WORKING-STORAGE AREAS DEFINED BY AN OCCURS CLAUSE

The program excerpt for this procedure is

ACCESSING WORKING-STORAGE AREAS DEFINED BY AN OCCURS CLAUSE

This procedure could also be written with a PERFORM . . . UNTIL or a PERFORM . . . TIMES. In all cases, an in-line PERFORM can be used as well.

Example 2: Using the same array, find the number of months in which the monthly total exceeded $10,000. The pseudocode and program excerpt for this procedure are

Structured Pseudocode

ACCESSING WORKING-STORAGE AREAS DEFINED BY AN OCCURS CLAUSE

Program Excerpt

ACCESSING WORKING-STORAGE AREAS DEFINED BY AN OCCURS CLAUSE

PROCESSING DATA STORED IN AN ARRAY

USING OCCURS WITH VALUE AND REDEFINES CLAUSES

Sometimes we want to initialize elements in a table or an array with specific values. Suppose we have an array where we want to set each element to a differ-

ent value. Because the VALUE clause can be used in conjunction with an OCCURS entry, a data-name called MONTH-NAMES could be written.

USING OCCURS WITH VALUE AND REDEFINES CLAUSES

In this instance, a 36-character array is established that consists of 12 three-position fields, the first containing JAN, the second containing FEB, . . . and the twelfth containing DEC.

USING OCCURS WITH VALUE AND REDEFINES CLAUSES

To print the appropriate three-character abbreviation for each month, we may use the following routine:

USING OCCURS WITH VALUE AND REDEFINES CLAUSES

REDEFINES Clause. The REDEFINES clause is an older method for defining this array. With this method, we define the 36-position storage area as one field with a VALUE of JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC. We then redefine that storage area into 12 separate array elements, using an OCCURS clause. As a result, each array element will have a different value.

USING OCCURS WITH VALUE AND REDEFINES CLAUSES

The first 05 field, MONTH-STRING, establishes a 36-position constant that contains a three-character abbreviation for each of the 12 months of the year. MONTH then redefines MONTH-STRING and enables each three-character abbreviation for months 1 through 12 to be accessed separately using a subscript. If we move MONTH (4), for example, to an output area, APR would print, which is an abbreviation for the fourth month. In this way, using the corresponding subscript can access each abbreviation for a month.

Once a field is defined, it can be redefined with an OCCURS clause. In addition, the first field, which is defined without an OCCURS clause, may have a VALUE clause that is used to establish a constant, if it is in the WORKING-STORAGE SECTION. Also, VALUE clauses can be used in conjunction with OCCURS entries.

PRINTING DATA STORED IN AN ARRAY

At the beginning of this chapter, we discussed a program that processed 24 hourly temperatures for a given city for a particular day. We used a PIC S9(3) clause with S, so any city's temperatures could be defined, even if the temperature fell below zero. The input record is defined as

PRINTING DATA STORED IN AN ARRAY

We could have several such records, each containing temperatures for a different day. Suppose that we want to print out on one line the 24 hourly temperature values in each input record. We can also use the OCCURS clause in an output record, as illustrated in the following program excerpt.

PRINTING DATA STORED IN AN ARRAY

TEMPERATURE-ENTRIES is a group field that consists of two elementary fields: TEMPERATURE-OUT and a 1-byte blank field. The second field is a separator, which is necessary so that there is a single blank between each temperature for readability. The layout for the print positions of TEMPERATURE-RECORD-OUT, then, is

PRINTING DATA STORED IN AN ARRAY

The preceding is a program that reads records, each with 24 hourly temperatures, and prints all 24 temperatures for each record on a single line. The program has two arrays, one for storing 24 hourly temperatures per input record and one for storing the same temperatures along with separator fields in the output area.

Suppose we wish to read in the same series of 24 hourly temperatures and print the highest temperature for each day. The input would be the same. The TEMPERATURE-RECORD-OUT and description for HIGHEST-TEMPERATURE in WORKING-STORAGE would be

PRINTING DATA STORED IN AN ARRAY

The MAIN-MODULE of the PROCEDURE DIVISION would be the same as the preceding. 200-PROCESS-RECORD-RTN and 220-MOVE-RTN would be

PRINTING DATA STORED IN AN ARRAY

Note that this program handles temperatures that could fall below zero degrees because the PIC for the temperatures contains an S. We initialize

HIGHEST-TEMPERATURE at −999, a negative number so low that the first TEMPERATURE (SUB) will exceed it and be moved to it as the first "real" entry. Alternatively, we could MOVE TEMPERATURE (1) TO HIGHEST-TEMPERATURE initially and PERFORM 220-MOVE-RTN VARYING SUB FROM 2 BY 1 UNTIL SUB > 24. The edited field, HIGHEST-TEMPERATURE-OUT, contains a minus sign that will print only if HIGHEST-TEMPERATURE-OUT happens to be negative.

If we wanted to print the number of hours in a day when the temperature dipped below 40 degrees, we would write our TEMPERATURE-RECORD-OUT as

PRINTING DATA STORED IN AN ARRAY

200-PROCESS-RECORD-RTN is the same, except that we INITIALIZE WS-COUNTER to zeros, not to HIGHEST-TEMPERATURE. 220-MOVE-RTN would be

PRINTING DATA STORED IN AN ARRAY

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

Consider the TEMPERATURE-FILE described in the preceding section. Suppose we wish to print 24 lines of output, each with an hourly temperature.

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

The TEMPERATURE-RECORD-OUT would appear as

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

The routine for printing 24 lines would be as follows, using an in-line PERFORM:

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

Suppose, instead, that we want to print 12 lines of output, each with an A.M. temperature and a P.M. temperature.

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

The program excerpt is

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

Suppose we wish to print two lines of output, the first with 12 A.M. temperatures and the second with 12 P.M. temperatures. The sample output is shown here:

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

The program excerpt is shown below. SUB1, used for subscripting TEMPERATURE, varies from 1 to 24 within 420-PRINT-RTN, and SUB2, used for subscripting TEMPERATURE-OUT, varies from 1 to 12 within 420-PRINT-RTN, which is executed twice, once for each output line.

PRINTING SUBSCRIPTED VARIABLES IN A VARIETY OF WAYS

The full program for printing the previous three examples is shown in Figure 15.4.

Program CPCH15B that prints temperatures.

Figure 15.4. Program CPCH15B that prints temperatures.

USING AN OCCURS CLAUSE FOR TABLE HANDLING

In this section, we focus on the OCCURS clause to store table data. As we will see, tables and arrays are stored in exactly the same way; they are, however, used for different purposes.

A table is a list of stored fields that are looked up or referenced by the program. Tables are used in conjunction with table look-ups, whereas a table look-up is a procedure that finds a specific entry in the table.

Thus, an array stores data or totals to be manipulated or outputted, whereas a table is used for looking up, or referencing, data.

WHY TABLES ARE USED

Suppose that a mail-order company ships items to customers throughout the country. A program is required that (1) reads customer input data containing billing information and (2) produces output in the form of bills. Since each county within the United States has a different local tax structure, a procedure must be established for calculating sales tax. Two techniques may be employed:

  1. The actual sales tax rate may be entered as part of each input record.

    Entering the sales tax rate in each input record would be very inefficient. First, sales tax rates occasionally change; each time there is a change to a tax rate in a county, all input records for that county would need to be changed. Second, recording the sales tax rate for each input record means extra keying. That is, if 1000 input records all pertain to a single county, we would need to enter the same sales tax rate 1000 times. This results in additional labor and added risk of input errors.

  2. The sales tax rates may be entered and stored in a table that can be referenced using a table look-up.

This is a far more efficient and effective method for storing tax rate data than the first method. Input to the program would consist of two files. The table file with sales tax rates corresponding to each county is entered as the first file and stored in WORKING-STORAGE. Then the input transaction file is read; for each input transaction record, we would find or look up the sales tax rate in the table that corresponds to the county specified in the input record.

Suppose there are 1000 tax rates and 10,000 customer records. To include a sales tax rate in each input record would require 10,000 additional fields to be entered as input. It is better to (1) enter and store the 1000 sales tax rates as a table and (2) look up the appropriate rate in the table for each input customer record.

Tip

DEBUGGING TIP

Table data is typically entered as a file and stored in a WORKING-STORAGE entry using an OCCURS clause. It could be established instead in WORKING-STORAGE directly as a fixed set of values; however, if the sales tax rates are likely to change over time, it is much better to enter them as input. Wherever possible, use input to enter variable data and establish constants only when the data is expected to remain unchanged.

STORING THE TABLE IN WORKING-STORAGE

To store a table, we must associate a sales tax rate with each specific tax district. We may use the Zip Code to identify each tax district.

Assume that a sales tax rate for each Zip Code is stored in a sales tax table.

STORING THE TABLE IN WORKING-STORAGE

The sales tax file is read first, with Zip Codes and sales tax rates, and stored in WORKING-STORAGE. Then the input customer file is read. The Zip Code from each customer record is compared to the Zip Code in the table until a match is found. The sales tax rate corresponding to a specific Zip Code is used to calculate a total price to be printed:

STORING THE TABLE IN WORKING-STORAGE

The SALES-TAX-TABLE consists of table entries, where each table entry is a group item subdivided into a Zip Code field and its corresponding sales tax rate. The table argument is the table entry field that is used to locate the desired element. Here, the table argument is the table's Zip Code field. The element to be looked up is called the table function. In this case, the table function is the table's sales tax rate. The input field in each transaction record that is used for finding a match is called the search argument. We compare the search argument to the table argument to find the table function. Consider the following example.

STORING THE TABLE IN WORKING-STORAGE

In this example, a Zip Code of 12344 is in the input transaction record. This is the search argument. We use this search argument to find the corresponding table argument, which is the Zip Code of 12344 in the table. The table function is the sales tax rate corresponding to that Zip Code, which is 8%, or ˆ080.

After the table is read in, and stored in, WORKING-STORAGE, we enter input transaction records. For each transaction record, we search the table to find the table argument that matches the transaction record's Zip Code, or search argument. When a match is found between the input transaction Zip Code (the search argument) and the table's Zip Code (the table argument), we know the table function or sales tax rate is the corresponding table entry. That is, if the fifth table argument is a Zip Code of 12344, then the sales tax rate we want is also the fifth entry in the table.

The program to produce the desired customer bills may be divided into two basic modules: (1) reading and storing the table and (2) processing each input record, which includes a field that is used for a table look-up.

Suppose this transaction file has customers from 1000 Zip Code locations. We would have, then, 1000 table records on disk with the following format:

STORING THE TABLE IN WORKING-STORAGE

The pseudocode for this problem is shown in Figure 15.5.

Pseudocode for sample table-handling routine.

Figure 15.5. Pseudocode for sample table-handling routine.

The TAX-FILE could be specified:

Pseudocode for sample table-handling routine.

Note that we do not indicate in the DATA DIVISION the number of table records that will be processed. That is, we do not use an OCCURS clause to denote the repeated occurrence of 1000 table records. Instead, in the PROCEDURE DIVISION the program performs the 120-TABLE-ENTRY module 1000 times. During each perform of 120-TABLE-ENTRY, a record is read from the TAX-FILE and loaded into the table.

Since table data must be stored before processing of the input customer file begins, a WORKING-STORAGE area is needed to hold the 1000 table entries:

Pseudocode for sample table-handling routine.

Because the word TABLE is a reserved word, it should not be used in a program as an identifier unless it has a prefix or suffix.

The WORKING-STORAGE table stores the 1000 entries:

Pseudocode for sample table-handling routine.

The main input file will contain customer billing or transaction data used to produce an output file of bills.

Pseudocode for sample table-handling routine.

000-MAIN-MODULE and 100-INITIALIZATION-RTN include references to both the 120-TABLE-ENTRY and 200-PROCESS-RECORD-RTN modules:

Pseudocode for sample table-handling routine.

Consider the PERFORM 120-TABLE-ENTRY statement. When SUB exceeds 1000, that is, when it is 1001, 120-TABLE-ENTRY has been performed 1000

times, and control returns to the initialization module. Since SUB, as a subscript, will vary from 1 to 1001, it must be defined as a four-position numeric field.

USING THE READ ... INTO TO LOAD A TABLE

A READ . . . INTO instruction is best suited for loading tables because it can take the place of a READ followed by multiple MOVEs.

USING THE READ ... INTO TO LOAD A TABLE

An initial READ is not necessary for processing the TAX-FILE because we know precisely how many table records are to be read. Since 1000 table entries are to be read and stored, we execute the 120-TABLE-ENTRY routine 1000 times by varying the subscript from 1 to 1001.

Subscripts must be used when referencing the table entries WS-ZIPCODE and WS-TAX-RATE in the PROCEDURE DIVISION. Recall that WS-ZIPCODE will be the table argument and WS-TAX-RATE the table function. We use a subscript name of SUB here for reasons that will become clear in the next section.

VALIDATING DATA

For this program, 1000 table records are to be read and stored. If an error has occurred and there are fewer than 1000 table records, the AT END is executed and the run terminates. If an error has occurred and there are more than 1000 table records, we would only process the first 1000. For validating purposes, we may want to ensure that there are precisely 1000 table records. The following can be written.

VALIDATING DATA

The DISPLAY verb is used, as shown here, to display brief messages to the user.

Sometimes we have a variable number of table entries, but we know that the number will not exceed a specific value. If, in the preceding, there are at most

1000 table entries, but there could be fewer, we replace the first IF in 100-INITIALIZATION-RTN with

VALIDATING DATA

Then, when we process the table we use NUMBER-OF-ENTRIES, not 1000, to control the maximum number of times we access the table. Suppose we want to know the number of Zip Codes that have a tax rate of 10 percent. The following would be written.

VALIDATING DATA

LOOKING UP DATA IN A TABLE: FINDING A MATCH

After the table entries have been stored in WORKING-STORAGE, we read customer billing data and produce bills. To find the sales tax rate, or table function, for each Zip Code, however, we must look up the Zip Code in the table (table argument) until it matches the Zip Code in the customer record (search argument). When a match is found between the table argument and the search argument, the corresponding sales tax rate (the table function) with the same subscript as the table's Zip Code will be used for calculating the sales tax. In the next section, we discuss how a table is searched using a SEARCH verb. In Figure 15.6, we use a PERFORM . . . UNTIL to search the table. We are assuming that the table has precisely 1000 entries.

Using a PERFORM ... UNTIL to search a table.

Figure 15.6. Using a PERFORM ... UNTIL to search a table.

USE OF THE SEARCH STATEMENT FOR TABLE AND ARRAY PROCESSING

FORMAT OF THE SEARCH STATEMENT

The best method for searching a table is with the use of a SEARCH statement. A basic format of the SEARCH is

Instruction Format

FORMAT OF THE SEARCH STATEMENT

The NEXT SENTENCE clause should be avoided with the WHEN clause. Also, If END-SEARCH is used, NEXT SENTENCE must be replaced with CONTINUE.

Using a SEARCH statement, the program to SEARCH the table would be

FORMAT OF THE SEARCH STATEMENT

The identifier used with the SEARCH verb is the table entry name specified on the OCCURS level, not on the 01 level. The WHEN clause indicates what action is to be taken when the condition specified is actually met. This condition compares an input field or search argument (ZIP-IN, in this example) with a table argument (WS-ZIPCODE (SUB), in this example). Additional comparisons between search and table arguments can be made using other WHEN clauses. We use END-SEARCH as a scope terminator. Note, however, that the NEXT SENTENCE clause cannot be used with an END-SEARCH scope terminator. A period is optional after END-SEARCH unless the END-SEARCH is the last entry in the paragraph.

USING THE SEARCH ... AT END FOR DATA VALIDATION

With the SEARCH statement, the AT END clause specifies what should be done if the table has been completely searched and no match is found. That is, suppose the ZIP-IN field does not match any WS-ZIPCODE field in the table; such a condition will cause the AT END clause to be executed if it is specified. Since it is possible for input errors to occur, we strongly recommend that you always use this optional clause. Without it, the "no match" condition would simply cause

the program to continue with the next sentence. This could produce incorrect results or even cause a program to terminate abnormally.

To use a SEARCH statement, two additional entries are required: the INDEXED BY clause, along with OCCURS, and the SET statement in the PROCEDURE DIVISION.

THE INDEXED BY CLAUSE AND THE SEARCH STATEMENT

When using a SEARCH statement, table entries must be specified with an index rather than a subscript. An index is similar to a subscript, but it is defined along with the table entries as part of the OCCURS description:

THE INDEXED BY CLAUSE AND THE SEARCH STATEMENT

As noted, the index, SUB in this illustration, functions like a subscript. Note, however, that unlike a subscript, an index is not defined separately in WORKING-STORAGE. It is defined with an INDEXED BY clause along with the OCCURS. The compiler automatically provides an appropriate PICTURE clause, in this case 9(4), since there are 1000 entries in the table.

The SEARCH statement will perform a table look-up. TABLE-ENTRIES, the identifier used with the OCCURS and INDEXED BY clauses, is the item designated with the SEARCH as well. The 01-level entry, SALES-TAX-TABLE, could not be used with the SEARCH.

The table will be searched and the index automatically incremented until the condition specified in the WHEN clause is satisfied or until an AT END condition is met. The AT END indicates that the table has been completely searched without the condition being met; that is, no match has been found between an input field (search argument) and a table entry (table argument). Frequently, we specify the AT END as:

SEARCH . . .
AT END
PERFORM 250-ERROR-RTN
WHEN. . . .

Note that the software developer must initialize an index before each SEARCH to start a table look-up at the first entry.

HOW AN INDEX DIFFERS FROM A SUBSCRIPT

The difference between a subscript and an index is worth noting because indexes are processed more efficiently than subscripts. As we have seen, a subscript is a field that refers to the number of the table entry we want to reference. Consider the following.

HOW AN INDEX DIFFERS FROM A SUBSCRIPT

An index for MONTHLY-SALES can be established with an INDEXED BY clause on the OCCURS level. Like a subscript, the index will, in effect, vary from 1 to 12. Internally, however, the computer uses displacement values to actually access indexed table entries. The first table entry has a displacement of zero bytes

from the start of the table, the second has a displacement of 3 bytes from the start of the table, and so on, with the last table entry having a displacement of 33 bytes from the start of the table:

HOW AN INDEX DIFFERS FROM A SUBSCRIPT

The displacement values used by an index depend on the number of bytes in each table entry, which is 3 in our example. To the software developer, it may not seem to make a difference whether we use a subscript or an index to access a table entry. The only difference is that a subscript is a separate WORKING-STORAGE entry, while the index is defined by an INDEXED BY clause on the OCCURS level. Both can have values from 1 to 12 in this example. An index, however, is processed more efficiently than a subscript. When you define an index, the computer sets up an internal storage area called an index register, which uses the displacement values determined by the index to access table addresses. This is faster than working with subscripts. We recommend, therefore, that you use indexes and SEARCH statements for table look-ups.

Because an index refers to a displacement and not just an occurrence value, its contents cannot be modified with a MOVE, ADD, or SUBTRACT like a subscript can. To change the contents of an index, then, we use either (1) a PERFORM . . . VARYING, which can vary the values in either subscripts or indexes, or (2) a SET statement, which can move, add, or subtract values in an index.

MODIFYING THE CONTENTS OF AN INDEX

THE SET STATEMENT

As noted, a subscript is a field defined separately in WORKING-STORAGE to access specific entries in an array. Its contents may be changed with the use of a PERFORM . . . VARYING and with a MOVE, ADD, or SUBTRACT statement.

As we have seen, an index is also used in a table look-up, but it is defined with an INDEXED BY clause that follows a table's OCCURS clause. The index must be specified if a SEARCH is used to perform the table look-up. It can be modified with a PERFORM . . . VARYING, too. Thus, loading the table with a 120-TABLE-ENTRY routine, as described previously, is still correct.

Although a PERFORM . . . VARYING may be used with an index, we may not modify the contents of an index with a MOVE, ADD, or SUBTRACT statement. Instead, we must use a SET statement to alter the contents of an index with any instruction other than the PERFORM . . . VARYING.

Basic Format

THE SET STATEMENT
THE SET STATEMENT

INITIALIZING AN INDEX BEFORE USING THE SEARCH

A SEARCH statement does not automatically initialize the index at 1 because sometimes we may want to begin searching a table at some point other than the beginning. A SET statement initializing an index to 1 must be performed prior to the SEARCH if we want to begin each table look-up with the first entry:

INITIALIZING AN INDEX BEFORE USING THE SEARCH

The following summarizes the differences between subscripts and indexes.

Subscript

Index

• Represents an occurrence of an array or table element

• Represents a displacement from the first address in the array or table

• Defined in a separate WORKING-STORAGE entry

• Defined along with the OCCURS for the array or table

• To change a subscript's value, use a PERFORM . . . VARYING or any of the following:

• To change an index value, use a PERFORM . . . VARYING or any of the following:

MOVE 1 TO SUB
ADD 1 TO SUB
SUBTRACT 1 FROM SUB
SET SUB TO 1
SET SUB UP BY 1
SET SUB DOWN BY 1

Tip

Debugging Tip

We recommend that you use INDEXED BY and SEARCH for table look-ups. Remember to SET SUB TO 1 before a SEARCH when you want to begin searching at the first table entry.

Once an INDEXED BY clause has been added to a table or array, the index can be used for loading data into the table or array as well as for searching the table or array. Consider the following table and assume that it has already been loaded.

INITIALIZING AN INDEX BEFORE USING THE SEARCH

Suppose we want to display the item description for PART-NUMBER 126. We could write

INITIALIZING AN INDEX BEFORE USING THE SEARCH

USING TWO WHEN CLAUSES FOR AN EARLY EXIT FROM A SEARCH

As you can see from the format for the SEARCH statement, multiple WHEN clauses are permitted. Let us consider an example.

Suppose the preceding INVENTORY-TABLE consists of 100 PARTS, where the PART-NUMBERs are in sequence but are not necessarily consecutive. That is, the first entry may be for PART-NUMBER 001, the second for PART-NUMBER 003, the third for PART-NUMBER 008, and so on. The PART-NUMBERs may not be consecutive because some parts may no longer be stocked, whereas newer ones with different numbers may have been added.

If we enter a PART-NUMBER-IN as input and wish to determine its UNIT-PRICE, we can write

USING TWO WHEN CLAUSES FOR AN EARLY EXIT FROM A SEARCH

Since the table is in sequence by PART-NUMBER, we could save computer time by exiting the SEARCH procedure as soon as a PART-NUMBER-IN > PART-NUMBER (SUB). Suppose PART-NUMBER-IN is 006, for example, and that PART-NUMBER (1) = 001, PART-NUMBER (2) = 003, and that PART-NUMBER (3) = 008. We would know after the third comparison that there is no match. Using the preceding routine, the program would search through all 100 entries before indicating 'NO MATCH.' For more efficient processing, we could use two WHEN clauses instead.

USING TWO WHEN CLAUSES FOR AN EARLY EXIT FROM A SEARCH

With two WHEN clauses, the program begins by performing the first comparison. Only if the condition in the first WHEN is not met does it test the second WHEN. That is, only if there is no match will a test be made to see if the search should be terminated and 'NO MATCH' displayed. There is no need for an AT END clause here because 'NO MATCH' will be displayed at some point. It will be displayed either when the end of the table is reached or as soon as a PART-NUMBER-IN is greater than some PART-NUMBER (SUB).

WHEN PART-NUMBERS DO NOT NEED TO BE STORED

If there were 100 PART-NUMBERs and they varied consecutively from 1 to 100, the PART-NUMBER would not have to be stored. We would know, for example, that UNIT-PRICE (5) refers to PART-NUMBER 005. Likewise, we know that ITEM-DESCRIPTION (10) refers to the description for PART-NUMBER 10.

To determine the unit price for a PART-NUMBER, where the numbers vary from 1 to 100, we could write

MOVE UNIT-PRICE (PART-NUMBER-IN) TO DL-UNIT-PRICE.

We could use the PART-NUMBER-IN as a subscript and eliminate the need for a SEARCH entirely. This type of table is called a direct-referenced table. In this example, INVENTORY-TABLE could only be a direct-referenced table if PART-NUMBERs varied consecutively from 1 to 100.

SEARCHING FOR MULTIPLE MATCHES

Sometimes we may want to search for multiple matches in a table. In such instances, it is better to use a PERFORM, rather than a SEARCH, statement for processing the entire table, because we want to continue processing the table even after a match is found. The SEARCH . . . WHEN looks up data from the table until a match is found, at which point the program continues with the next sentence. A PERFORM . . . VARYING can be used to process an entire table even after a match is found. Suppose we want to know the item descriptions for all parts with a unit price greater than 100.00. We could write

SEARCHING FOR MULTIPLE MATCHES

INTERNAL VERSUS EXTERNAL TABLES

Thus far, we have focused on tables that are inputted as data from disk before transaction records are entered. We read in tables in this way when their contents are likely to change periodically. When tables are stored on disk, their contents can be changed as the need arises without having to make modifications to the program accessing the table. Such tables are called external tables.

If the contents of a table is fixed, that is, not likely to change, we can define it with VALUE clauses directly in the WORKING-STORAGE section. In this way, we

need not read it in each time. Consider the MONTH-NAMES entry we defined previously.

INTERNAL VERSUS EXTERNAL TABLES

The subscripted variables MONTH(1) through MONTH(12) can be used for accessing the month names JAN through DEC, respectively, without the need for loading a table with the 12 month names. This is called an internal table since it is actually part of the program. We store month names in an internal table because the values are not likely to change.

Tip

Debugging Tip

If table entries are expected to remain fixed, define them directly in the program using an internal table. When table data changes periodically, use an external table.

LOOKING UP TABLE DATA FOR ACCUMULATING TOTALS

We have illustrated how to add values to an array and how to look up data in a table. In this section, we combine both techniques.

Suppose a store has 25 charge account customers, each with his or her own customer number (CUSTOMER-NUMBER). We want to read in transaction records and print the accumulated BALANCE-DUE for each customer. If the CUSTOMER-NUMBERs vary from 1 to 25, we need only store 25 BALANCE-DUEs in an array.

LOOKING UP TABLE DATA FOR ACCUMULATING TOTALS

This would be another illustration of a direct-referenced array, where BALANCE-DUE(CUSTOMER-NUMBER-IN) can be used to access specific balances. The CUSTOMER-NUMBERs need not be stored because they vary from 1 to 25. The procedure to add to the appropriate BALANCE-DUE would be

LOOKING UP TABLE DATA FOR ACCUMULATING TOTALS

CUSTOMER-ARRAY is a direct-referenced array because BALANCE-DUE (1) refers to the first CUSTOMER-NUMBER, BALANCE-DUE (2) refers to the second CUSTOMER-NUMBER, and so on. This type of direct-referenced array is valid only if CUSTOMER-NUMBERs vary consecutively from 1 to 25.

Suppose, however, that the CUSTOMER-NUMBERs for the 25 customers are not consecutive. For this situation, you need to store the CUSTOMER-NUMBERs as well as accumulate the total BALANCE-DUE for each customer. The 200-ADD-TO-BALANCE procedure could use a SEARCH to find a specific CUSTOMER-NUMBER and add to the corresponding BALANCE-DUE.

LOOKING UP TABLE DATA FOR ACCUMULATING TOTALS

The SEARCH has two WHEN clauses. If a customer number already appears in the array, an existing T-CUSTOMER-NUMBER (SUB) will equal the CUSTOMER-NUMBER-IN. Then we simply add AMOUNT-IN to the corresponding T-BALANCE-DUE (SUB). If the CUSTOMER-NUMBER-IN does not match an existing T-CUSTOMER-NUMBER in the table, then the first T-CUSTOMER-NUMBER with a zero will be replaced with the CUSTOMER-NUMBER-IN and the AMOUNT-IN will become the T-BALANCE-DUE for that customer. If 25 customer numbers are

already stored in the array and a customer number is entered as input that does not match any of them, then an error message will be displayed.

LOOKING UP TABLE DATA FOR ACCUMULATING TOTALS

This illustration shows how to process nonconsecutive customer numbers that must be stored along with the accumulated balances. It also shows how to use two separate WHEN clauses in a SEARCH.

Figure 15.7 illustrates the full program. Note that the program will not print CUSTOMER-NUMBERs in sequence unless they were entered in sequence.

COBOL program CPCH15D, which uses two WHEN statements.

Figure 15.7. COBOL program CPCH15D, which uses two WHEN statements.

THE SEARCH ... VARYING OPTION FOR PROCESSING PARALLEL TABLES

The following is an alternative way of processing tables. If the customer numbers were not consecutive but we knew in advance what they were, we could store them in a separate table.

THE SEARCH ... VARYING OPTION FOR PROCESSING PARALLEL TABLES

Then we can store the balances due in a separate array.

THE SEARCH ... VARYING OPTION FOR PROCESSING PARALLEL TABLES

These would be parallel tables with the CUSTOMER-NUMBER-TABLE storing 25 customer numbers and the CUSTOMER-BALANCE-ARRAY storing the corresponding BALANCE-DUE for each:

THE SEARCH ... VARYING OPTION FOR PROCESSING PARALLEL TABLES

When the program reads CUSTOMER-NUMBER-IN, it searches CUSTOMER-NUMBER-TABLE to determine which entry to add to in CUSTOMER-BALANCE-ARRAY. We can use the SEARCH . . . VARYING option for processing parallel arrays.

THE SEARCH ... VARYING OPTION FOR PROCESSING PARALLEL TABLES

This technique enables us to enter CUSTOMER-NUMBERs into one table and store BALANCE-DUEs in a corresponding parallel table. Since the CUSTOMER-NUMBERs are not consecutive, a direct-referenced CUSTOMER-ARRAY cannot be used. Note, too, that the output report would be in sequence only if the CUSTOMER-NUMBERs entered as input are in sequence.

We use SUB1, the index of the parallel table, in the SEARCH . . . VARYING, not the index of CUSTOMER-NUMBER-TABLE. The SEARCH . . . VARYING has the following format.

Instruction Format

THE SEARCH ... VARYING OPTION FOR PROCESSING PARALLEL TABLES

* The NEXT SENTENCE clause is not permitted with the END-SEARCH.

DEFINITION OF A SERIAL SEARCH

Thus far, we have discussed the method of table look-up called a serial search.

A sequential or serial search, as described here, is best used when either

  1. The entries in a table are not in either ascending or descending sequence; that is, they are arranged randomly; or,

  2. Table entries are organized so that the first values are the ones encountered most frequently; in this way, access time is minimized because you are apt to end the search after the first few comparisons.

THE BINARY SEARCH

In many instances the table entries are arranged in some numeric sequence. In a DISCOUNT-TABLE, for example, the table entries are apt to be in ascending sequence by customer number:

DISCOUNT-TABLE

 

T-CUSTOMER-NUMBER

T-DISCOUNT-PCT

Customer number → is in ascending sequence

0100

2.0

 

0200

1.0

 

0400

5.0

 

.

.

 

.

.

 

.

.

The table contains the discount percentage to which each customer is entitled. Note that although the customer numbers are in sequence, they are not necessarily consecutive, so we must store the T-CUSTOMER-NUMBER as well as the T-DISCOUNT-PCT.

We could write the table as

THE BINARY SEARCH

In this table, a discount of 2.0 percent, for example, is stored as ˆ020.

In cases where the entries in a table are in some sequence, a serial search may be inefficient. For example, it would be time-consuming to begin at the first table entry when searching for the T-DISCOUNT-PCT for customer number 9000. Since the table is in sequence, we know that customer number 9000 is somewhere near the end of the table; hence, beginning with the first entry and proceeding in sequence would waste time.

DEFINITION OF A BINARY SEARCH

When table entries are arranged in sequence by some field, such as T-CUSTOMER-NUMBER, the most efficient type of look-up is a binary search. Following is the way the computer performs a binary search.

On average, a binary search on a table that is in sequence by some field takes fewer comparisons to find a match than does a serial search.

Example

Suppose CUSTOMER-NUMBER-IN = 5000

Binary Search

CUSTOMER-NUMBER-IN matches T-CUSTOMER-NUMBER when the thirty-fourth entry of the table is compared. If a serial search were used, 34 comparisons would be required. The binary search method, however, requires only four comparisons in this instance. In general, for tables with 50 or more entries in sequence by some field, a binary search will save time.

This alternative method for table look-ups is called a binary search because each comparison eliminates one-half the entries under consideration; that is, each comparison reduces the entries to be searched by a factor of two.

A binary search is preferable to a serial search:

  1. When table entries are arranged in some sequence—either ascending or descending.

  2. When tables with a large number of sequential entries (e.g., 50 or more) are to be looked up or searched.

For small tables or those in which entries are not arranged in a sequence, the standard serial search look-up method previously described is used. For large tables in which entries are arranged in a specific sequence, the binary search is most efficient. It is difficult to define a "large" table explicitly, but let us say that any table containing more than 50 entries that are in some sequence could benefit from the use of a binary search.

THE SEARCH ALL STATEMENT

The SEARCH ALL statement is used to perform a binary search. The format of the SEARCH ALL is very similar to that of the SEARCH.

Basic Format

THE SEARCH ALL STATEMENT

*NEXT SENTENCE cannot be used with END-SEARCH.

A SET statement is not necessary with the SEARCH ALL, since the computer sets the index to the appropriate point initially when each binary search begins. Consider the following example.

THE SEARCH ALL STATEMENT

Note that there are a number of limitations placed on the use of a binary search using a SEARCH ALL statement. First, binary searches can be used only with WHEN clauses that test for equal conditions between a table argument and a search argument. That is, the syntax for a SEARCH ALL requires the WHEN to use = (not <, >, <=, or >=) as the relational test.

This means that you must use a serial search when the look-up checks for a range of entries rather than a single match, even if the table is in sequence. Suppose we want to find a UNIT-PRICE that is <= 100.00, where table entries are in sequence by UNIT-PRICE.

THE SEARCH ALL STATEMENT

Using a serial search, the first entry would be <= 100.00 and the search would be completed. If a binary search were permitted, the middle entry, 25, meets the condition (e.g., UNIT-PRICE (25) < 100.00), so the search would be completed after the first test. A binary search, then, would produce a different match than a serial search.

Because we are using a less-than (<) test, going to the midpoint of the table with a SEARCH ALL statement does not really help. It tells us that UNIT-PRICE (25) < 100.00, but UNIT-PRICE (1) could also be < 100.00, as could UNIT-PRICE (2), and so on. Note, then, that a binary search cannot be used for anything but tests for equality (e.g., WHEN search argument = table argument).

The following summarizes the major limitations to a SEARCH ALL.

ASCENDING OR DESCENDING KEY WITH THE SEARCH ALL STATEMENT

To use the SEARCH ALL statement, we must indicate which table entry will serve as the key field. That is, we specify the table entry that will be in sequence so that the binary search can be used to compare against that field. We must indicate whether that KEY is ASCENDING or DESCENDING.

 

KEY FIELD

ASCENDING KEY

Entries are in sequence and increasing in value.

DESCENDING KEY

Entries are in sequence and decreasing in value.

The ASCENDING or DESCENDING KEY is specified along with the OCCURS and INDEXED BY clauses of a table entry when a SEARCH ALL is to be used, as shown in the following example.

ASCENDING OR DESCENDING KEY WITH THE SEARCH ALL STATEMENT

The identifier used in the ASCENDING KEY clause must be an entry within the table. If entries in the table decrease in value, then DESCENDING KEY would be used. In either case, the ASCENDING or DESCENDING KEY clause must be included and it must appear before the INDEXED BY clause.

In this example, T-CUSTOMER-NUMBER increases in value as we move through the table; hence, T-CUSTOMER-NUMBER is used with an ASCENDING KEY clause.

Tip

Debugging Tip

The table must be in sequence by the KEY field to perform a valid binary search. If you specify ASCENDING KEY IS PART-NUMBER, the computer will not check that part numbers are correctly sequenced but will assume that this is so. If the part numbers are not in sequence in the table, a binary search will give unpredictable results.

For best results, the KEY entries or table arguments should be unique; that is, no two table arguments (such as T-CUSTOMER-NUMBER) should have the same value. If it happens, however, that two table arguments defined in an ASCENDING or DESCENDING KEY clause have identical values and one of them is to be accessed, it is difficult to predict which one the computer will use for the look-up with a SEARCH ALL. With a serial SEARCH, the first entry will be the one that is designated as a match.

Differences Between the SEARCH and the SEARCH ALL

SEARCH

SEARCH ALL

Performs a serial search

Performs a binary search

Table entries need not be in any sequence

Table entries must be in sequence by the table argument or even the table function. The field that is in sequence is specified in an ASCENDING or DESCENDING KEY clause as part of the OCCURS entry

Requires a SET statement prior to the SEARCH to specify the starting point for the look-up

Does not need a SET prior to the SEARCH ALL

Can include any relational test with the WHEN clause (<, >, =, <=, >=) or any compound conditional

Can have only a single = condition tested with the WHEN clause

May include multiple WHEN clauses

May only have one WHEN clause

END-OF-CHAPTER AIDS

CHAPTER SUMMARY

  1. OCCURS clauses

    1. Are used in the DATA DIVISION to specify the repeated occurrence of items with the same format.

    2. May be written on levels 02–49.

    3. May specify an elementary or group item.

  2. Use an OCCURS clause to define arrays and tables.

    1. Array: an area used for storing data or totals.

    2. Table: a set of fields used in a table look-up.

  3. Use of the SEARCH statement for table-handling:

    1. The identifier used with the SEARCH verb is the one specified on the OCCURS level.

    2. The AT END clause specifies what is to be done if the table has been searched and the required condition has not been met.

    3. The WHEN clause indicates what to do when the condition is met.

    4. When using a SEARCH statement, table entries are specified with the use of an index, rather than a subscript.

    5. The index is defined along with the OCCURS. For example: 01 UNIT-PRICE-TABLE.

      05 STORED-ENTRIES OCCURS 500 TIMES

      INDEXED BY SUB.

    6. An index cannot be modified with a MOVE, ADD, or SUBTRACT statement. Use a SET statement when altering the contents of an index, or use the PERFORM . . . VARYING.

    7. The index is SET to 1 to 1 before using a SEARCH.

    8. Use a PERFORM . . . VARYING to load the table.

  4. The SEARCH ALL statement—uses and limitations.

    1. Used to perform a binary search.

    2. Can test only an equal condition.

    3. If using a compound condition: (a) each part can test only an equal condition and (b) only ANDs are permitted.

    4. Only one WHEN clause can be used.

    5. The ASCENDING or DESCENDING KEY is specified along with the OCCURS and INDEXED BY clauses of a table entry.

KEY TERMS

Array

Binary search

Direct-referenced table

External table

Index

INDEXED BY

Internal table

OCCURS clause

Relative subscript

SEARCH

SEARCH ALL

Search argument

Serial search

Subscript

Table

Table argument

Table function

Table look-up

CHAPTER SELF-TEST

TRUE-OR-FALSE QUESTIONS

  • 1. A subscript may be either a data-name or an integer.

  • 2. An item defined by an OCCURS may be a group item that is further divided into elementary items.

  • 3. The identifier used with the SEARCH verb is the table-entry specified on the 01 level.

  • 4. A SEARCH statement automatically initializes the index at 1.

  • 5. The SEARCH ALL statement is used to perform a serial search.

  • 6. A SET statement is not necessary with the SEARCH ALL statement.

  • 7. If an input record contained 10 group items, each with a three-digit elementary item followed by a four-digit elementary item, then an OCCURS clause could be used to define the input fields.

  • 8. An input field may not be used as a subscript.

  • 9. Data can be either moved or added to an array.

  • 10. After a WHEN condition has been met in a SEARCH, the index contains the number of the element that resulted in a match.

  • 11. When the SEARCH ALL statement is used, the table must be in either ASCENDING or DESCENDING sequence.

  • 12. SEARCH ALL is used for a binary search.

  • 13. An index used in a SEARCH may be initialized by a MOVE statement.

  • 14. A binary search is always preferable to a serial search.

  • 15. The condition specified in a WHEN clause usually compares a table argument to a search argument.

FILL-IN-THE-BLANKS QUESTIONS

  1. A serial search of a table begins with the (first/middle/last) entry in the table, whereas a binary search of a table begins with the (first/middle/last) entry.

  2. The SEARCH ALL statement requires that a(n) ___clause be specified along with the OCCURS and INDEXED BY clauses of a table entry.

    Consider the following for questions 3 and 4.

    FILL-IN-THE-BLANKS QUESTIONS
  3. If we print EACH-DAY(3), ___will print.

  4. When using a SEARCH statement, table entries must be specified with the use of a(n) ___, rather than a subscript.

  5. Consider the following.

FILL-IN-THE-BLANKS QUESTIONS
  1. An OCCURS clause could be used in place of defining each AMOUNT field separately because ___.

  2. To access any of the five items defined with the OCCURS clause, we must use a ___ in the PROCEDURE DIVISION.

CHAPTER REVIEW QUESTIONS

GENERAL QUESTIONS

  1. What, if anything, is wrong with the following?

    GENERAL QUESTIONS
  2. Indicate the difference between the following.

    GENERAL QUESTIONS
  3. Consider the following total area in WORKING-STORAGE.

    GENERAL QUESTIONS

    For ease of processing, this total area lists the Dow-Jones industrial average for 365 days, from January 1 through December 31 of a given year, including weekends and national holidays. Assume that the year in question was not a leap year. Print the number of days on which the Dow-Jones industrial average fell below 3400.

  4. What, if anything, is wrong with the following SEARCH?

    GENERAL QUESTIONS
  5. Suppose the following entry has been specified.

    GENERAL QUESTIONS
    1. Write a statement to initialize the index at 1.

    2. Write a SEARCH statement to look up the table entries in FIELDS until FIELD1 = 123, at which time 230-PROCESS-TABLE-DATA is to be performed.

  6. Indicate what, if anything, is wrong with the following.

    GENERAL QUESTIONS
  7. Consider the following.

    GENERAL QUESTIONS

    Suppose there are exactly 100 PART-NUMBERs with values 001–100. Do we need to store PART-NUMBER?

  8. Indicate the differences between a SEARCH and a SEARCH ALL.

  9. For the following table:

    1. Find both the largest and the smallest state population figures.

    2. Print the state number of each state with a population in excess of 2,250,000 people.

    3. Write a routine to print the total number of states that have populations smaller than 2,250,000.

    GENERAL QUESTIONS
  10. Using the following table:

    1. Write a routine to print the name of the state with the largest population.

    2. Write a routine to print the population for Wyoming.

GENERAL QUESTIONS

DEBUGGING EXERCISES

  1. Consider the following.

    DEBUGGING EXERCISES

    There are two major logic errors in this program excerpt.

    1. After the table has been loaded, you find that 200-PROCESS-RECORD-RTN is not performed. That is, the run is terminated after the table is loaded. Find the error and correct it.

    2. After receiving an obscure interrupt message, you DISPLAY TABLE-IN entries and find that only the last nine have been loaded. Find the error and correct it.

  2. Consider the following 700-SEARCH-RTN excerpt (not part of Exercise 1 above).

    DEBUGGING EXERCISES
    1. A program interrupt will occur the first time through 700-SEARCH-RTN. Find and correct the error.

    2. A program-interrupt will occur if there is no match between PART-NUMBER-IN and T-PART-NUMBER. Find and correct the error.

    3. Suppose INVENTORY-ENTRIES is defined as follows.

DEBUGGING EXERCISES

This will cause two syntax errors on lines 22 and 24. Find and correct these errors.

PRACTICE PROGRAM

The personnel department at a university wishes to print a report identifying each employee's full title, department name, and campus name, not just the codes. The program will use table look-ups to find the appropriate items from separate title, department, and campus tables.

Suppose the university has five campuses identified as

Code

Campus

1

Upstate

2

Downstate

3

City

4

Melville

5

Huntington

Since the five campuses and their codes are not likely to change, we can store them as an internal table, that is, entered with VALUEs rather than as variable data. Since the campus codes vary consecutively from 1 to 5, we need not store the codes themselves in the internal table, which can be a direct-referenced table:

PRACTICE PROGRAM

Department codes have changed over time so that, while there are 25 departments, they range in number from 01–96. The numbers are not consecutive, so we cannot establish this as a direct-referenced table. Moreover, since department names and department numbers change, we need to create a DEPARTMENT-TABLE as an external table:

PRACTICE PROGRAM

We will enter data into DEPARTMENT-TABLE using a PERFORM . . . VARYING. We will use a SEARCH to determine department names, since our table is really too small to benefit from a SEARCH ALL, even if the data is in sequence by T-DEPARTMENT-NUMBER.

There are 50 TITLE codes ranging from 001–986. They are not consecutive, so we establish a table that stores the TITLE-NUMBER along with the TITLE-NAME. The table will be accessed with a SEARCH ALL because we will enter the data in

TITLE-CODE sequence and the table is large enough to benefit from a binary search.

PRACTICE PROGRAM

In this program, then, we will use three different methods for establishing tables and looking up data from them. The following is the pseudocode for the problem.

Structured Pseudocode

PRACTICE PROGRAM

PROGRAMMING ASSIGNMENTS

  1. Using the file definition for the sales transaction file below, write a program to print total sales for each salesperson.

    Printer spacing chart for sales report

    PROGRAMMING ASSIGNMENTS

    Record description layout for sales transaction file

    Field Description

    Type

    Size

    COBOL Field-name

    Salesperson Number

    S

    2,0

    SALESPERSON-NUMBER

    Salesperson Name

    A

    20

    SALESPERSON-NAME

    Amount Of Sales

    P

    7,2

    AMOUNT-OF-SALES

    Notes:

    1. There are 20 salespeople, numbered 1 to 20.

    2. Each sale that is made is used to create one input record; thus, there may be numerous input records for each salesperson if he or she made more than one sale.

    3. Input records are not in sequence. (If they were, you could use a control break procedure.)

    4. Print the total sales figure for each salesperson; thus, although the number of input records is variable, the output will consist of 20 totals.

    5. All total fields should be edited.

  2. Consider the problem definition below.

    Printer spacing chart for monthly salary report

    PROGRAMMING ASSIGNMENTS

    Record description layout for salary file

    Field Description

    Type

    Size

    COBOL Field-name

    Employee Number

    S

    2,0

    SALESPERSON-NUMBER

    Employee Name

    A

    20

    SALESPERSON-NAME

    Annual Salary

    P

    7,0

    ANNUAL-SALARY

    Number Of Dependents

    P

    2,0

    NUMBER-OF-DEPENDENTS

    Record description layout for tax table

    Field Description

    Type

    Size

    COBOL Field-name

    Maximum Taxable Income

    P

    7,0

    MAXIMUM-TAXABLE-INCOME

    Federal Tax

    P

    3,3

    FEDERAL-TAX

    State Tax Rate

    P

    3,3

    STATE-TAX-RATE

    Notes:

    1. Monthly take-home pay is to be computed for each employee. A tax table must be read into main storage from 20 table records, which are read before the SALARY-FILE.

      Example:

      Taxable Income($)

      Federal Tax

      State Tax

      09800

      .040

      .010

      12000

      .080

      .020

      The state tax is 1 percent and the federal tax is 4 percent for taxable income less than or equal to $9800; for a taxable income between $9801 and $12,000 (inclusive), the state tax is 2 percent and the federal tax is 8 percent, and so on.

    2. After the table is read and stored, read a salary record. Monthly net pay is computed as follows:

    3. Standard deduction = 10 percent of the first $10,000 of annual salary

    4. Dependent deduction = 2000 times number of dependants

    5. FICA (Social Security tax) = 7.65 percent of the first $57,600 of annual salary. There is a Medicare tax of 1.45 percent on salaries from $57,600 to $135,000.

    6. Taxable income = Annual salary – standard deduction - dependent deduction

    7. Find the tax for the taxable income, using the tax table.

    8. Annual take-home pay = Annual salary – (state tax percentage x taxable income) – (federal tax percentage x taxable income) – FICA vii. Monthly take-home pay = Annual take-home pay/12

    9. Print each employee's name and the corresponding monthly net pay (edited).

  3. A vehicle registration report is to be printed as follows:

    Printer spacing chart for vehicle registration report

    PROGRAMMING ASSIGNMENTS

    Record description layout for vehicle registration file

    Field Description

    Type

    Size

    COBOL Field-name

    Vehicle Class

    S

    2,0

    VEHICLE-CLASS

    Name

    A

    20

    NAME

    Weight Of Vehicle

    P

    5,0

    WEIGHT-OF-VEHICLE

    Vehicle Description

    A

    15

    VEHICLE-DESCRIPTION

    Record description layout for registration table

    Field Description

    Type

    Size

    COBOL Field-name

    Vehicle Class

    S

    2,0

    VEHICLE-CLASS

    Registration Rate

    P

    3,3

    REGISTRATION-RATE

    Notes:

    1. There are 90 table entries, one for each vehicle class.

    2. After the table is read and stored, read in the vehicle registration file.

    3. c For each record, the vehicle class must be found in the table to obtain the corresponding registration rate.

    4. Registration fee = vehicle weight x registration rate (from the table).

  4. Write a program to read in employee records with the following format.

    Record description layout for employee file

    Field Description

    Type

    Size

    COBOL Field-name

    Employee Number

    S

    9,0

    EMPLOYEE-NUMBER

    Employee Name

    A

    20

    EMPLOYEE-NAME

    Annual Salary

    P

    7,0

    ANNUAL-SALARY

    Job Classification

    S

    1,0

    JOB-CLASSIFICATION

    Notes:

    1. Job classifications vary from 1 to 9.

    2. The records are in no particular sequence.

    3. Print a report that lists the average annual salary for each job classification.

  5. Interactive Processing. Write an interactive program that

    1. Loads into a table each student's Social Security number, the number of credits completed, and his or her GPA from the student file:

      Record description layout for student file

      Field Description

      Type

      Size

      COBOL FIELD-NAME

      Social Security Number

      S

      9,0

      SOCIAL-SECURITY-NUMBER

      Number of Credits Completed

      P

      3,0

      NUMBER-OF-CREDITS-COMPLETED

      Current GPA

      P

      3,2

      CURRENT-GPA

    2. There is a maximum of 500 student records in the file.

    3. Enables users to interactively enter a Social Security number, the number of courses taken this semester (maximum of 5), and the grades for each course.

    4. Has the program interactively display the new GPA.

    5. All courses are three credits, and A = 4, B = 3, C = 2, D = 1, and F = 0.

Example: A student currently has a 3.0 GPA with 90 credits. This semester, the student took four courses and received two As, one B, and one C:

A × 6 credits = 4 × 6 =

24

B × 3 credits = 3 × 3 =

9

C × 3 credits = 2 × 3 =

6

 

39

Previous credits: (90 × 3.0) =

270

Total

309

Divide 309 by total credits taken (102) = 3.03

The new GPA displayed for this student should thus be 3.03.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset