COBOL OCCURS Clause How to Code Correctly

Suppose you want to store your monthly sales figures for the year. You could define twelve fields, one for each month, like this:

1. COBOL OCCURS clause

05  MONTHLY-SALES-1    PIC S9(5)V99.    
05  MONTHLY-SALES-2    PIC S9(5)V99.   
05  MONTHLY-SALES-3    PIC S9(5)V99.   
05  MONTHLY-SALES-11   PIC S9(5)V99.   
05  MONTHLY-SALES-12   PIC S9(5)V99.

But there’s an easier way in COBOL.  You can specify the field once and declare that it repeats 12 times. You do this with the OCCURS clause, like this:


(By now you should also know this can be written on two lines like this):

05  MONTHLY-SALES  OCCURS 12 TIMES                                      PIC S9(5)V99.

This specifies 12 fields, all of which have the same PIC, and is called a table (also called an array).  The individual fields are referenced in COBOL by using subscripts, such as “MONTHLY-SALES(1)”.  This table occupies 84 bytes in the record (12 * (5+2)). (The sign is embedded, not separate, and the decimal is implied.).

2. The OCCURS can also be at the group level

And this is the most useful application of OCCURS.  For example, all 25 line items on an invoice (75 fields) could be held in this group:

10  QUANTITY            PIC 9999.       
10  DESCRIPTION         PIC X(30).       
10  UNIT-PRICE          PIC S9(5)V99.

Notice the OCCURS is listed at the group level, so the entire group occurs 25 times. The order of the data in the file is as-if you had specified multiple groups, like this:

05  LINE-ITEMS-1.        
10  QUANTITY            PIC 9999.       
10  DESCRIPTION         PIC X(30).       
10  UNIT-PRICE          PIC S9(5)V99.   
05  LINE-ITEMS-2.       
10  QUANTITY            PIC 9999.       
10  DESCRIPTION         PIC X(30).       
10  UNIT-PRICE          PIC S9(5)V99.       
05  LINE-ITEMS-25.       
10  QUANTITY            PIC 9999.       
10  DESCRIPTION         PIC X(30).     
10  UNIT-PRICE          PIC S9(5)V99.

3. There can be nested occurs

An occurs within an occurs.  In the next example, suppose we stock ten products andwe want to keep a record of the monthly sales of each product for the past 12 months. We could do just that with this table:


In this case, “INVENTORY-ITEM” is a group composed only of “MONTHLY-SALES”, which occurs 12 times for each occurrence of an inventory item.  This gives an array (table) of 10 * 12 fields.  The only information in this record are the 120 monthly sales figures — 12 months for each of 10 items.

We could also have a description for each item. The description would go under the 05 level INVENTORY-ITEM group, at the 10 level, the same as the monthly sales.  Further, we could track, say, the sale price of each item for each month.  A record which will do these things is:

 01  INVENTORY-RECORD.        
10  ITEM-DESCRIPTION               PIC X(30).          
10  MONTHLY-SALES OCCURS 12 TIMES.               
15  QUANTITY-SOLD              PIC 999.             
15  UNIT-PRICE                 PIC 9(5)V99.

Notice we have made MONTHLY-SALES a group, which now contains two fields, and the whole group repeats 12 times for each instance of INVENTORY-ITEM. 

This short layout has 250 fields: two fields (QUANTITY-SOLD and UNIT-PRICE) that repeat 12 times for each inventory item, times 10 items, plus the ITEM-DESCRIPTION field for each of the 10 items.  Fields and groups can be nested several levels deep, and it’s possible to have thousands of fields in a layout only a couple pages long.

4. Occurs Depending On

One really great feature of COBOL tables, and a really nasty one to convert to other languages, is the “OCCURS DEPENDING ON”.  This is an OCCURS, like above, but the number of times it occurs in a particular record can vary (between some limits).

The number of times it actually occurs in any particular record will be given by a value in another field of that record. This creates records that vary in size from record to record.

The OCCURS-DEPENDING-ON can include many subordinate fields and groups, all of which occur multiple times.  Further, most compilers allow one or more (fixed) OCCURS to be nested within an OCCURS-DEPENDING-ON, and some compilers allow multiple OCCURS-DEPENDING-ON to be nested, or to occur in succession. 

This can get pretty involved, so we will only give one simple example, that of a patient’s medical treatment-history record .

05  PATIENT-NAME                PIC X(30).    
   05  PATIENT-SS-NUMBER           PIC 9(9).       
10  TREATMENT-DATE.          
15  TREATMENT-DAY        PIC 99.            
   15  TREATMENT-MONTH      PIC 99.               
15  TREATMENT-YEAR       PIC 9(4).          
10  TREATING-PHYSICIAN       PIC X(30).        
10  TREATMENT-CODE           PIC 99.

Here are the significant points of this record:

  • The name of the record is “PATIENT-TREATMENTS”.
  • The first three fields “PATIENT-NAME”, “PATIENT-SS-NUMBER”, and “NUMBER-OF-TREATMENTS” occur in the fixed portion of every record.  This fixed portion is the same for every record.
  • The TREATMENT-HISTORY group is the variable portion of the record. It can occur from 0 to 50 times.
  • “”NUMBER-OF-TREATMENTS” is a number from 0 to 50 that tells us how many times the group TREATMENT-HISTORY occurs in this record.
  • The value in NUMBER-OF-TREATMENTS is stored in a comp-3 packed format. This is very common. Also very common is comp or binary format.  All of these are binary data formats.
  • TREATMENT-HISTORY is a group that is comprised of all the lower level fields beneath it. (Down to the next 05 level, or the end of the record).
  • All the fields and groups within TREATMENT-HISTORY occur between 0 and 50 times.
  • Because 0 is a valid number of occurrences, it is possible the variable portion of the record is not present.
  • The “INDEXED BY TREATMENT-POINTER” clause may or may not be present.  If present it tells the compiler the name of the variable (TREATMENT-POINTER) to use as the index into the array.  If you don’t understand this, you can safely ignore the “indexed by…” clause, unless you are programming in COBOL.
  • TREATMENT-DATE is a group that is comprised of the day, month, and year fields beneath it.
  • These records vary in size from 41 to 2041 bytes, and would be stored in some type of variable length file.

Ref TekTalk

Related Posts

Latest from the Blog

SQL Query: How to Use LOCATE and Substring Correctly

Here are SQL queries to use the SUBSTRING function along with LOCATE function. LOCATE gives position, and SUBSTRING uses that for the start position.

Python Logic to use tell() and seek()

In Python, both tell and seek functions help you get the data from a file. How to use these explained on how to use in your current project.

Author: Srini

Experienced software developer. Skills in Development, Coding, Testing and Debugging. Good Data analytic skills (Data Warehousing and BI). Also skills in Mainframe.