Filling an Empty Table

The tables that we have seen in this course have all had the data setup in Working Storage and then redefined to turn the data into a table. This approach is valid for table data that is fairly stable such as state names and department names. When the data changes, the internal table must be modified and the program recompiled and tested before it is put back into production.

If the data is fluid, the programmer frequently decides to set up the table as an empty table and read the data that will fill the table prior to each execution of the program. The data that will be used to fill the table can be read in a variety of ways:

  1. the data can be keyed onto the disk containing the data as the first few records on the disk - this means that the data to fill the table is keyed in and then the regular data to be processed is keyed in - the resulting disk file would contain records to be used in filling the table followed by records to be processed - this approach is appropriate when the table data is very volatile and you want fresh data prior to running the program (See approach #1)
  2. the data can be keyed in and stored on a disk file that will be used in conjunction with the regular data disk file each time the processing program is executed - if this approach is taken, there must also be some way to update the table disk if the data needs to be changed (otherwise anytime something changed a whole new file would have to be created) - this approach is appropriate when the data changes periodically, not for every run (see approach #2)
  3. the data can be keyed in on the screen at the beginning of the program prior to the processing of the file - this approach is appropriate when the data is very volatile and the programmer wants current data prior to running the program (see approach #3)

Examples:

In the examples we will assume that we are doing an inventory pricing program and that we want to fill a table with the price of the 6 items that we carry.

The first 6 records on the file contain data to fill the table. (There is one record for each of the 6 items that we carry).


			1 - 3  Item Number
			4 - 7  Price

Starting with record 7, the regular data is read:

               1 -  4  Customer Number
               5 -  7  Item Number
               8 - 12  Number Ordered


Note that the records are of different lengths. Because it is more efficient to work with files of fixed record length, the programmer will add a 5 character filler to the table layout making it 12 characters. Now both types of records have the same length.

Approach #1:

There are two record types which need to be defined. The programmer can either define them both in the FD, both in Working Storage or one in the FD and one in Working Storage. All three approaches will be covered:

1/ Both in the FD:

FD  DATA-FILE
    DATA RECORDS ARE TABLE-INPUT, REGULAR-INPUT.
01  TABLE-INPUT.
    05  ITEM-NUM-TI          PIC 9(3).
    05  PRICE-TI             PIC 99V99.
    05  FILLER               PIC X(5).
01  REGULAR-INPUT.
    05  CUST-NUM-IN          PIC 9(4).
    05  ITEM-NUM-IN          PIC 9(3).
    05  NUM-ORD-IN           PIC 9(5).

Two 01 levels in the FD works as if one 01 was a redefinition of the other. COBOL does not allow the redefines on the 01 level of the FD but does provide this alternative which works the same way as far as the programmer is concerned. Note that the name of both 01 layouts are listed in the documentation clause DATA RECORDS ARE TABLE-INPUT, REGULAR-INPUT.

The reading of both the first six table records and the regular records would be handled with the regular read statement:

		READ DATA-FILE
			AT END
				MOVE 'NO ' TO MORE-RECS.

2/ Both in WORKING-STORAGE:

In this example, both records have been defined in working storage, but an area must still be reserved in the 01 level of the FD because the record is read into this area before the contents of the record is moved to the working storage area.

FD  DATA-FILE
    DATA RECORD IS DATA-INPUT.
01  DATA-INPUT              PIC X(12).
...
...
...

WORKING-STORAGE SECTION.
01  TABLE-INPUT.
    05  ITEM-NUM-TI          PIC 9(3).
    05  PRICE-TI             PIC 99V99.
    05  FILLER               PIC X(5).
01  REGULAR-INPUT.
    05  CUST-NUM-IN          PIC 9(4).
    05  ITEM-NUM-IN          PIC 9(3).
    05  NUM-ORD-IN           PIC 9(5).


The read statements for the data both require the INTO clause, which moves the data from the input area (01 level of FD) to the working storage area named after the INTO clause.

READ statement for the table data:


		READ DATA-FILE INTO TABLE-INPUT
			AT END
				MOVE 'NO ' TO MORE-RECS.

READ statement for the regular data:

		READ DATA-FILE INTO REGULAR-INPUT
			AT END
				MOVE 'NO ' TO MORE-RECS.

3/ One in the FD AND one in WORKING-STORAGE:

FD  DATA-FILE
    DATA RECORD IS REGULAR-INPUT.
01  REGULAR-INPUT.
    05  CUST-NUM-IN          PIC 9(4).
    05  ITEM-NUM-IN          PIC 9(3).
    05  NUM-ORD-IN           PIC 9(5).
...
...
...

WORKING-STORAGE SECTION.
01  TABLE-INPUT.
    05  ITEM-NUM-TI          PIC 9(3).
    05  PRICE-TI             PIC 99V99.
    05  FILLER               PIC X(5).  

NOTE: I decided to keep the regular data in the FD and put the table data in working storage. I could have done it the other way around.

When reading the data, different read statements would be used to handle reading the table data and reading the regular data.

Reading the table data:

		READ DATA-FILE INTO TABLE-INPUT
			AT END
				MOVE 'NO ' TO MORE-RECS.

The READ statement reads the record into the FD/01, and the INTO clause moves the record into the area called TABLE-INPUT. The record is actually now in two places, but we will use it from the WORKING-STORAGE area only.

Reading the regular data:

	READ DATA-FILE
			AT END	
				MOVE 'NO ' TO MORE-RECS.

Other work areas that must be defined are the subscripts. I need a subscript to control filling the table which I will call SUB-IN. After looking at the ITEM-NUMBER data, it is clear that the item numbers cannot be used as a direct subscript or pointer so I will need one subscript to control the search. I prefer to use different subscripts since they serve two purposes, so I will call the subscript for the search SUBZ.

01  SUBSCRIPTZ.
    05  SUB-IN         PIC 9       VALUE 1.
    05  SUBZ           PIC 9       VALUE 0.


The table must also be set up in the working storage area. The table is an empty table that will receive data from the first six records on the input file. Therefore, I do not need to set up the values for the table, I simply need to define six empty slots which I will fill when I start processing.

01  ITEM-TABLE.
    05  ENTRIES OCCURS 6 TIMES.
        10  ITEM-NUM-T         PIC 9(3).
        10  PRICE-T            PIC 99V99.


In the PROCEDURE DIVISION, I need to accomplish the following tasks:

  1. fill the table from the first six records on the file
  2. process the regular data
A-100-INITIALIZE.
    OPEN INPUT DATA-FILE...
    MOVE 1 TO SUB-IN.      (can eliminate if value is 1)
    PERFORM U-100-FILL-TABLE
        6 TIMES.            or UNTIL SUB-IN > 6.
B-100-PROCESS.
    READ... (read used to read regular data)
    PERFORM B-200-LOOP
        UNTIL NO-MORE-RECS.
B-200-LOOP.
    PERFORM B-300-DETAIL.
    READ... (read used to read regular data)
B-300-DETAIL.
    check for headers (if needed perform B-400-HDRS)
    MOVE SPACES TO PRINTZ.
    MOVE CUST-NUM-IN TO CUST-NUM-PR.
    MOVE ITEM-NUM-IN TO ITEM-NUM-PR.
    MOVE 1 TO SUBZ.
    MOVE 'NO ' TO MATCH-IND.
    PERFORM B-410-SEARCH
       UNTIL SUBZ > 6 OR MATCH-IS-FOUND.
    IF MATCH-IS-FOUND
       MOVE PRICE-T (SUBZ) TO PRICE-PR
       MULTIPLY PRICE-T (SUBZ) BY NUM-ORD-IN
          GIVING AMT-DUE-WS
       MOVE AMT-DUE-WS TO AMT-DUE-PR
    ELSE
       MOVE 0 TO PRICE-PR
       MOVE 0 TO AMT-DUE-PR
       MOVE ERR-MSG-CONST TO MSG-AREA-PR.
    WRITE PRINTZ
       AFTER ADVANCING 1 LINES.
    ADD 1 TO LNCT.
B-400-HDRS.
    routine to write headers
B-410-SEARCH.
    IF ITEM-NUM-IN = ITEM-NUM-T (SUBZ)
        MOVE 'YES' TO MATCH-IND
    ELSE
        ADD 1 TO SUBZ.
U-100-FILL-TABLE.
    READ... (read for table data)
    MOVE ITEM-NUM-TI TO ITEM-NUM-T (SUB-IN).
    MOVE PRICE-TI TO PRICE-T (SUB-IN).
    ADD 1 TO SUB-IN.


This program has a new version of the PERFORM. The PERFORM U-100-FILL-TABLE 6 TIMES command means that the named paragraph will be performed 6 times. After the sixth time through the paragraph, control will move on to the next instruction. In the example, the number of times is given as a numeric literal. The programmer can also define a field, for example CT, and have the perform done CT TIMES.

SYNTAX:

	PERFORM  paragraph-name
		{literal      }
                       {dataname} TIMES.

Approach #2:

The second approach is very similiar to approach #1 - the difference is that two input files are involved. The first input file will contain the data for the table and the second input file will contain the regular data. Therefore there will be two selects and two Fds, one for each file.

FD  TABLE-FILE
    DATA RECORD IS TABLE-INPUT.
01  TABLE-INPUT.
    05  ITEM-NUM-TI          PIC 9(3).
    05  PRICE-TI             PIC 99V99.
    05  FILLER               PIC X(5).
FD  REGULAR-FILE
    DATA RECORD IS REGULAR-INPUT.
01  REGULAR-INPUT.
    05  CUST-NUM-IN          PIC 9(4).
    05  ITEM-NUM-IN          PIC 9(3).
    05  NUM-ORD-IN           PIC 9(5).


Note: In this example, both file layouts are setup in the FILE SECTION. When you code the program, you could define the layout for either file in the FILE SECTION or in the WORKING-STORAGE SECTION. The only requirement is for the FD and the 01 level to be defined in the FILE SECTION.

The subscripts and the table setup would be the same as in approach #1:

01  SUBSCRIPTZ.
    05  SUB-IN         PIC 9       VALUE 1.
    05  SUBZ           PIC 9       VALUE 0.
01  ITEM-TABLE.
    05  ENTRIES OCCURS 6 TIMES.
        10  ITEM-NUM-T         PIC 9(3).
        10  PRICE-T            PIC 99V99.


The code to fill the table would vary slightly from that in Approach #1:

A-100-INITIALIZE.
    OPEN INPUT TABLE-FILE
               REGULAR-FILE...
    MOVE 1 TO SUB-IN.     
    PERFORM U-100-FILL-TABLE
        UNTIL EOF-TABLE = "YES" OR SUB-IN > 6.
    can include error processing if you want to end the
    program if the table does not get properly filled
    (EOF-TABLE = "YES")
B-100-PROCESS.
    READ REGULAR-FILE
        AT END 
           MOVE "YES" TO EOF-REGULAR.
    PERFORM B-200-LOOP
        UNTIL NO-MORE-RECS.
B-200-LOOP.
    PERFORM B-300-DETAIL.
    READ REGULAR-FILE
        AT END
           MOVE "YES" TO EOF-REGULAR.
B-300-DETAIL.
    check for headers (if needed perform B-400-HDRS)
    MOVE SPACES TO PRINTZ.
    MOVE CUST-NUM-IN TO CUST-NUM-PR.
    MOVE ITEM-NUM-IN TO ITEM-NUM-PR.
    MOVE 1 TO SUBZ.
    MOVE 'NO ' TO MATCH-IND.
    PERFORM B-410-SEARCH
       UNTIL SUBZ > 6 OR MATCH-IS-FOUND.
    IF MATCH-IS-FOUND
       MOVE PRICE-T (SUBZ) TO PRICE-PR
       MULTIPLY PRICE-T (SUBZ) BY NUM-ORD-IN
          GIVING AMT-DUE-WS
       MOVE AMT-DUE-WS TO AMT-DUE-PR
    ELSE
       MOVE 0 TO PRICE-PR
       MOVE 0 TO AMT-DUE-PR
       MOVE ERR-MSG-CONST TO MSG-AREA-PR.
    WRITE PRINTZ
       AFTER ADVANCING 1 LINES.
    ADD 1 TO LNCT.
B-400-HDRS.
    routine to write headers
B-410-SEARCH.
    IF ITEM-NUM-IN = ITEM-NUM-T (SUBZ)
        MOVE 'YES' TO MATCH-IND
    ELSE
        ADD 1 TO SUBZ.
U-100-FILL-TABLE.
    READ TABLE-FILE
        AT END
           MOVE "YES" TO EOF-TABLE.
    MOVE ITEM-NUM-TI TO ITEM-NUM-T (SUB-IN).
    MOVE PRICE-TI TO PRICE-T (SUB-IN).
    ADD 1 TO SUB-IN.

Approach #3:

In this approach, the regular data file is set up either in the File Section or in the Working-Storage section just like any other file is setup.

FD  REGULAR-FILE
    DATA RECORD IS REGULAR-INPUT.
01  REGULAR-INPUT.
    05  CUST-NUM-IN          PIC 9(4).
    05  ITEM-NUM-IN          PIC 9(3).
    05  NUM-ORD-IN           PIC 9(5).


A screen to take in the data for the table is setup in the Screen Section. When the data is keyed in, the programmer has two alternatives:

Alternative #1: the program can be set up to take the data that is keyed in and store it in Working Storage prior to moving it to the table

WORKING-STORAGE SECTION.
01  DATA-KEYED-IN.
    05  ITEM-NUM-WS      PIC 9(3).
    05  PRICE-WS         PIC 99V99.
SCREEN SECTION.
01  PRICE-SCR.
    05  VALUE "SCREEN TO TAKE IN PRICE TABLE"
                                 LINE 1 COL 30.
    05  VALUE "ITEM NUMBER:"     LINE 4 COL 10.
    05  ITEM-DEF                 LINE 4 COL 25
             PIC 999    TO ITEM-NUM-WS.
    05  VALUE "PRICE:"           LINE 6 COL 10.
    05  PRICE-DEF                LINE 6 COL 25
             PIC 99V99  TO PRICE-WS.   
    ...
    ...


Alternative #2: the program can set up the screen section so that the data that is keyed in goes directly to the table.

SCREEN SECTION.
01  PRICE-SCR.
    05  VALUE "SCREEN TO TAKE IN PRICE TABLE"
                                 LINE 1 COL 30.
    05  VALUE "ITEM NUMBER:"     LINE 4 COL 10.
    05  ITEM-DEF                 LINE 4 COL 25
             PIC 999    TO ITEM-NUM-T (SUB-IN).
    05  VALUE "PRICE:"           LINE 6 COL 10.
    05  PRICE-DEF                LINE 6 COL 25
             PIC 99V99  TO PRICE-T (SUB-IN).   
    ...


The subscripts and the table setup would be the same as in Approach #1 and Approach #2:

01  SUBSCRIPTZ.
    05  SUB-IN         PIC 9       VALUE 1.
    05  SUBZ           PIC 9       VALUE 0.
01  ITEM-TABLE.
    05  ENTRIES OCCURS 6 TIMES.
        10  ITEM-NUM-T         PIC 9(3).
        10  PRICE-T            PIC 99V99.


The code to fill the table:

A-100-INITIALIZE.
    OPEN INPUT REGULAR-FILE...
    MOVE 1 TO SUB-IN.     
    PERFORM U-100-FILL-TABLE
	   6 TIMES.
B-100-PROCESS.
    READ REGULAR-FILE
        AT END 
           MOVE "YES" TO EOF-REGULAR.
    PERFORM B-200-LOOP
        UNTIL NO-MORE-RECS.
B-200-LOOP.
    PERFORM B-300-DETAIL.
    READ REGULAR-FILE
        AT END
           MOVE "YES" TO EOF-REGULAR.
B-300-DETAIL.
    check for headers (if needed perform B-400-HDRS)
    MOVE SPACES TO PRINTZ.
    MOVE CUST-NUM-IN TO CUST-NUM-PR.
    MOVE ITEM-NUM-IN TO ITEM-NUM-PR.
    MOVE 1 TO SUBZ.
    MOVE 'NO ' TO MATCH-IND.
    PERFORM B-410-SEARCH
       UNTIL SUBZ > 6 OR MATCH-IS-FOUND.
    IF MATCH-IS-FOUND
       MOVE PRICE-T (SUBZ) TO PRICE-PR
       MULTIPLY PRICE-T (SUBZ) BY NUM-ORD-IN
          GIVING AMT-DUE-WS
       MOVE AMT-DUE-WS TO AMT-DUE-PR
    ELSE
       MOVE 0 TO PRICE-PR
       MOVE 0 TO AMT-DUE-PR
       MOVE ERR-MSG-CONST TO MSG-AREA-PR.
    WRITE PRINTZ
       AFTER ADVANCING 1 LINES.
    ADD 1 TO LNCT.
B-400-HDRS.
    routine to write headers
B-410-SEARCH.
    IF ITEM-NUM-IN = ITEM-NUM-T (SUBZ)
        MOVE 'YES' TO MATCH-IND
    ELSE
        ADD 1 TO SUBZ.


The FILL-TABLE routine varies depending on whether Alternative #1 or Alternative #2 are used. Alternative #1 took the data in and stored it in WORKING-STORAGE prior to moving it to the table. Alternative #2 took the data in and move it directly to the table. The FILL-TABLE routine for both alternatives is shown:

Alternative #1:

U-100-FILL-TABLE.
    DISPLAY PRICE-SCR.
    ACCEPT PRICE-SCR.
    MOVE ITEM-NUM-WS TO ITEM-NUM-T (SUB-IN).
    MOVE PRICE-WS TO PRICE-T (SUB-IN).
    ADD 1 TO SUB-IN.


Alternative #2:

U-100-FILL-TABLE.
    DISPLAY PRICE-SCR.
    ACCEPT PRICE-SCR.
    ADD 1 TO SUB-IN.


In alternative #2, the data on the screen moves directly to the table because to TO clause has the name of the field on the table modified by the subscript. The first time through, SUB-IN will be 1, so the data keyed in will go to the first slots in the table. Then 1 is added to SUB-IN so the next time the routine is performed, the data will go to the second slots in the table.

Editing the data

It should be noted that the sample program does not edit the data for accuracy. In a production program this code should definitely be added. If invalid data is allowed into the table, the output from the program will reflect the bad data and be invalid as well.