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 Number | Item Name |
03 | SEAFOOD CHOWDER |
12 | CORN CHOWDER |
15 | CLAM CHOWDER |
17 | TOMATO SOUP |
24 | CHICKEN SOUP |
25 | VEGETABLE SOUP |
27 | ONION SOUP |
28 | GREEN PEA SOUP |
45 | WONTON 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:
- set up the search - (1) set the search subscript in Working Storage that
will successively point to each element in the table to 1 and (2) initialize the match
indicator that will tell whether or not the search was successful to NO
- perform the search - perform the search routine which checks an item in
the table until either a match is found (set the match indicator to YES) or all of the
items in the table have been checked
- process according to the outcome of the search - the search is terminated
either by a match being found, in which case the match indicator will be set to YES or by
all of the elements in the table being checked - when the search is over, the indicator
will tell what caused it to end - if the indicator has been set to YES then the search was
successful and the processing that should be done if a match was found is executed - if the
indicator has stayed NO, the search was not successful and error processing should be
executed
The B-300-SEARCH includes the code to:
- Check for a match between the input and the items in the table - this
routine checks the item number on the input (ITEM-NUMBER-IN) against one of the item
numbers in the table (ITEM-NUMBER-TBL). Each time this routine is executed it will
compare to a different item number in the table. This is accomplished by using ITEM-SUB
which starts at 1 and is increased by one every time this routine is executed
- Processing if match is found - if a match is found, the match indicator
is set to YES - this accomplishes two things: (1) the routine will not be executed again
since one of the conditions that terminates the perform is MATCH-IND = "YES" and (2) it
will indicate that the search was successful and trigger appropriate processing
- Processing if match is not found - if a match is not found, ITEM-SUB is
increased by 1 so that the next time through the B-300-SEARCH the comparison will be with
the next item in the table
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.