Searching a Table

The tables that we have looked at have all involved extracting information from the table using a pointer or subscript that was defined on the input. The subscript was a numeric field with numbers starting at 1 that could be used to point to an item in the table. This kind of subscript is called a DIRECT SUBSCRIPT meaning that the subscript as it is defined can be used as a direct pointer to extract data from the table.

If the program is dealing with data that requires a table, but there is no field that can be used as a DIRECT SUBSCRIPT, then it is necessary for the programmer to define a table that can be SEARCHed using an INDIRECT SUBSCRIPT.

Indirect subscript and a search

The following example sets up a situation where a DIRECT SUBSCRIPT is inappropriate, so the programmer must SEARCH the table using an INDIRECT SUBSCRIPT as the pointer. The search that is needed can be done with the SEARCH VERB or with code developed by the programmer. Some COBOL compilers do not support the SEARCH VERB and sometimes the search is too complex to use the verb, therefore a programmer must be able to use their own code to develop a search. Since understanding the COBOL search code is critical to understanding the concept, the SEARCH VERB will be dealt with last.

This example will deal with a information that is to be set up in a table so that the programmer can use the item number on the input to retrieve the item name from the table and print it on the detail line. The programmer is provided with the following list showing what item number goes with what item name:

Item NumberItem Name
03SEAFOOD CHOWDER
12CORN CHOWDER
15CLAM CHOWDER
17TOMATO SOUP
24CHICKEN SOUP
25VEGETABLE SOUP
27ONION SOUP
28GREEN PEA SOUP
45WONTON SOUP


In this example, the item numbers are spread out rather than clustered at the beginning of the number sequence. The item number cannot be used as a DIRECT SUBSCRIPT. Instead, after setting up the table in Working-Storage, the programmer must write code to search the table using an INDIRECT SUBSCRIPT. Because the search will involve comparing the item number on the input to the item number in the table, the item number must be included with the item name in the table that is set up. Notice that this is a major difference from a table where a DIRECT SUBSCRIPT can be used. In those tables the item number would not have been included in the table.

The approach is to read the item number on the input and compare it to the first item number entry in the table which in our example is 03, if it does not match, we move down and compare the item number on the input to the second item number entry in the table which in our example is 12. This pattern continues until either a match is found or there are no more table entries to check. To do this, we need to set up a subscript or pointer in the WORKING-STORAGE SECTION that we can use to point to the first entry in the table and then the second etc. We also need to set up an indicator to tell us whether or not the search was successful.

FILE SECTION.
FD  INPUT-FILE.
01  INPUT-REC.
    ...
    05  ITEM-NUMBER-IN   PIC 99.
    ...
WORKING-STORAGE SECTION
01  SUBSCRIPTS.
    05  ITEM-SUB      PIC 99      VALUE 0.
01  INDICATORS.
    05  MATCH-IND     PIC XXX     VALUE "NO ".
Next, lets look at the table or tables that the programmer will need to set up in the WORKING-STORAGE SECTION. Remember, the item number must be kept in the table so that the program can compare it to the item number on the input. Clearly, the item number is also in the table since the purpose of the table is to access the item name and print it on the line. The programmer can either establish one table containing both the item number and the item name or two tables, one containing the item number and one containing the item name. My very strong preference is to establish one table containing both, but I will cover both approaches. Note that the search and processing in the PROCEDURE DIVISION are the same no matter which setup method is chosen.

01  TABLE-COMBINED.
    05  FILLER    PIC X(17)  VALUE "03SEAFOOD CHOWDER".
    05  FILLER    PIC X(17)  VALUE "12CORN CHOWDER   ".
    05  FILLER    PIC X(17)  VALUE "15CLAM CHOWDER   ".
    05  FILLER    PIC X(17)  VALUE "17TOMATO SOUP    ".
    05  FILLER    PIC X(17)  VALUE "24CHICKEN SOUP   ".
    05  FILLER    PIC X(17)  VALUE "25VEGETABLE SOUP ".
    05  FILLER    PIC X(17)  VALUE "27ONION SOUP     ".
    05  FILLER    PIC X(17)  VALUE "28GREEN PEA SOUP ".
    05  FILLER    PIC X(17)  VALUE "45WONTON SOUP    ".
01  RDF-TABLE-COMBINED REDEFINES TABLE-COMBINED.
    05  ENTRIES   OCCURS 9 TIMES.
        10  ITEM-NUMBER-TBL      PIC 99.
        10  ITEM-NAME-TBL        PIC X(15).
With this method, the item number is stored right next to the item name so it is easy to see which number goes with which name.

Notice what happens when the table is redefined. The 05 level indicates that there are 9 entries and on the 10 level each entry is broken down so that the first two characters are given the name ITEM-NUMBER-TBL and the last 15 characters are given the name ITEM-NAME-TBL. This means that the item number and the item name can be accessed separately (ENTRIES accesses the combined data).

The other approach to setting up this information uses two tables: one for item number and one for item name.

01  TABLE-ITEM-NUMBERS.
    05  FILLER    PIC 99  VALUE 03.
    05  FILLER    PIC 99  VALUE 12.
    05  FILLER    PIC 99  VALUE 15.
    05  FILLER    PIC 99  VALUE 17.
    05  FILLER    PIC 99  VALUE 24.
    05  FILLER    PIC 99  VALUE 25.
    05  FILLER    PIC 99  VALUE 27.
    05  FILLER    PIC 99  VALUE 28.
    05  FILLER    PIC 99  VALUE 45.
01  RDF-TABLE-ITEM-NUMBERS REDEFINES TABLE-ITEM-NUMBERS.
    05  ITEM-NUMBER-TBL      PIC 99   OCCURS 9 TIMES.

01  TABLE-NAMES.
    05  FILLER    PIC X(15)  VALUE "SEAFOOD CHOWDER".
    05  FILLER    PIC X(15)  VALUE "CORN CHOWDER   ".
    05  FILLER    PIC X(15)  VALUE "CLAM CHOWDER   ".
    05  FILLER    PIC X(15)  VALUE "TOMATO SOUP    ".
    05  FILLER    PIC X(15)  VALUE "CHICKEN SOUP   ".
    05  FILLER    PIC X(15)  VALUE "VEGETABLE SOUP ".
    05  FILLER    PIC X(15)  VALUE "ONION SOUP     ".
    05  FILLER    PIC X(15)  VALUE "GREEN PEA SOUP ".
    05  FILLER    PIC X(15)  VALUE "WONTON SOUP    ".
01  RDF-TABLE-NAMES REDEFINES TABLE-NAMES.
    05  ITEM-NAME-TBL        PIC X(15)   OCCURS 9 TIMES.
After the table or tables have been set up, the entries in the WORKING-STORAGE SECTION are complete. The next step is to code the two PROCEDURE DIVISION routines: one routine that will control the search and direct the processing steps after the search is complete depending on whether or not the search was successful and one routine that will actually do the search.

Search

In the B-200-LOOP, when you are setting up the print line, you need the item name to move to the print line. The item name is contained in the table, so you must search the table to find a match to the item number on the input and then move the corresponding item name to the print line. Before doing the search, some preliminary housekeeping must be done. The subscript being used for the search must be set to 1 and the MATCH-IND used to tell whether a match was found is set to NO. The search is performed until either the subscript is greater than 9 which indicates that all 9 elements in the table have been checked without finding a match or until the MATCH-IND is set to YES. When the search is over, the program needs to know what condition triggered the end of the search (MATCH-IND = "YES" or ITEM-SUB >9). If a match was found, the corresponding name will me moved from the table to the print line. This will be done using ITEM-SUB. If the match was found when ITEM-SUB = 4 then the statement MOVE ITEM-NAME-TBL (ITEM-SUB) will move the 4th name in the table. If a match was not found then an error message defined in WORKING-STORAGE will be moved.

The search itself happens in B-300-SEARCH. The search compares the item number on the input to the item number in the table that the ITEM-SUB subscript is pointing to. If the two numbers match, then the MATCH-IND is set to YES. If the two numbers do not match, the ITEM-SUB is increased by one so that the next time this paragraph is performed the subscript will point down one item.

Notice that every time the perform is done, the UNTIL clause will check to see if the subscript has passed the limit of 9. If the limit were passed, the subscript would be out of bounds or out of the range of the table and the program would about. When working with tables, the programmer needs to always keep control of the subscript so that it never goes out of the range of the table.

The code for the search:

B-200-LOOP.
    ...
    ... processing not related to search ...
    ...
    MOVE 1 TO ITEM-SUB.
    MOVE "NO " TO MATCH-IND.
    PERFORM B-300-SEARCH
        UNTIL ITEM-SUB > 9 OR MATCH-IND = "YES".
    IF MATCH-IND = "YES"
        MOVE ITEM-NAME-TBL (ITEM-SUB) TO ITEM-NAME-PR
    ELSE
        MOVE ERROR-MSG-TBL TO ITEM-NAME-PR.
    ...
    ... processing not related to search...
    ...
B-300-SEARCH.
    IF ITEM-NUMBER-IN = ITEM-NUMBER-TBL (ITEM-SUB)
        MOVE "YES" TO MATCH-IND
    ELSE
        ADD 1 TO ITEM-SUB.

The B-200-LOOP includes the code to:

The B-300-SEARCH includes the code to:

Notice that the B-300-SEARCH is being performed until one of two conditions is met and that both these conditions are changed in the B-300-SEARCH routine itself. In other words, the MATCH-IND can be changed to YES if a match is found and the ITEM-SUB is increased by 1 each time that a match is not found. This is a very important point to understand. The perform of the routine is done until one of two conditions is met and these conditions both can change within the routine that is being performed so that the perform will eventually terminate.