OCCURS

Overview

The OCCURS clause in COBOL is used to define tables (arrays) by specifying how many times a data item should be repeated. It enables the creation of homogeneous data structures that can be accessed using subscripts or indexes, providing powerful capabilities for processing lists, tables, and repetitive data structures in business applications.

Syntax Forms

*> Fixed OCCURS
level-number data-name OCCURS integer TIMES [clauses].

*> OCCURS DEPENDING ON
level-number data-name OCCURS min-times TO max-times TIMES 
    DEPENDING ON data-name-2 [clauses].

*> OCCURS with INDEXED BY
level-number data-name OCCURS integer TIMES 
    INDEXED BY index-name-1 [index-name-2 ...] [clauses].

*> OCCURS with KEY
level-number data-name OCCURS integer TIMES
    [ASCENDING|DESCENDING] KEY IS data-name-3 [data-name-4 ...]
    [INDEXED BY index-name-1 ...] [clauses].

Basic OCCURS Usage

Simple Table Definition

01  MONTHLY-SALES-TABLE.
    05  MONTHLY-SALES       OCCURS 12 TIMES PIC 9(7)V99.

01  STUDENT-GRADES.
    05  GRADE-ENTRY         OCCURS 50 TIMES PIC 999.

01  EMPLOYEE-TABLE.
    05  EMPLOYEE-RECORD     OCCURS 100 TIMES.
        10  EMP-ID          PIC 9(6).
        10  EMP-NAME        PIC X(25).
        10  EMP-SALARY      PIC 9(6)V99.

PROCEDURE DIVISION.
    *> Accessing table elements
    MOVE 15000.50 TO MONTHLY-SALES (1).
    MOVE 18000.75 TO MONTHLY-SALES (12).
    
    MOVE 85 TO GRADE-ENTRY (1).
    MOVE 92 TO GRADE-ENTRY (25).
    
    MOVE 123456 TO EMP-ID (1).
    MOVE "JOHN SMITH" TO EMP-NAME (1).
    MOVE 50000.00 TO EMP-SALARY (1).

Basic table definitions with fixed occurrences.

Multi-Dimensional Tables

01  SALES-MATRIX.
    05  QUARTERLY-DATA      OCCURS 4 TIMES.
        10  MONTHLY-DATA    OCCURS 3 TIMES.
            15  DAILY-SALES OCCURS 31 TIMES PIC 9(6)V99.

01  GRADE-MATRIX.
    05  CLASS-DATA          OCCURS 10 TIMES.
        10  STUDENT-DATA    OCCURS 30 TIMES.
            15  SUBJECT-GRADES OCCURS 5 TIMES PIC 999.

PROCEDURE DIVISION.
    *> Accessing multi-dimensional elements
    MOVE 1250.00 TO DAILY-SALES (1, 1, 1).     *> Q1, Jan, Day 1
    MOVE 1850.75 TO DAILY-SALES (4, 3, 31).    *> Q4, Mar, Day 31
    
    MOVE 95 TO SUBJECT-GRADES (1, 1, 1).       *> Class 1, Student 1, Subject 1
    MOVE 87 TO SUBJECT-GRADES (10, 30, 5).     *> Class 10, Student 30, Subject 5

Creating and accessing multi-dimensional table structures.

OCCURS DEPENDING ON

Variable Length Tables

01  TRANSACTION-RECORD.
    05  TRANS-COUNT         PIC 99.
    05  TRANSACTION-DETAILS OCCURS 1 TO 50 TIMES
                           DEPENDING ON TRANS-COUNT.
        10  TRANS-TYPE      PIC X(8).
        10  TRANS-AMOUNT    PIC 9(8)V99.
        10  TRANS-DATE      PIC 9(8).

01  INVOICE-DATA.
    05  LINE-COUNT          PIC 999.
    05  INVOICE-LINES       OCCURS 1 TO 999 TIMES
                           DEPENDING ON LINE-COUNT.
        10  ITEM-CODE       PIC X(15).
        10  DESCRIPTION     PIC X(40).
        10  QUANTITY        PIC 9(5).
        10  UNIT-PRICE      PIC 9(7)V99.
        10  TOTAL-PRICE     PIC 9(9)V99.

PROCEDURE DIVISION.
    *> Setting up variable length tables
    MOVE 5 TO TRANS-COUNT.
    MOVE 25 TO LINE-COUNT.
    
    PERFORM VARYING WS-INDEX FROM 1 BY 1 
            UNTIL WS-INDEX > TRANS-COUNT
        MOVE "PURCHASE" TO TRANS-TYPE (WS-INDEX)
        MOVE 100.00 TO TRANS-AMOUNT (WS-INDEX)
    END-PERFORM.

Using OCCURS DEPENDING ON for flexible table sizes.

Dynamic Array Processing

01  CUSTOMER-ORDER.
    05  ITEM-COUNT          PIC 999.
    05  ORDER-ITEMS         OCCURS 1 TO 100 TIMES
                           DEPENDING ON ITEM-COUNT.
        10  PRODUCT-ID      PIC X(10).
        10  PRODUCT-NAME    PIC X(30).
        10  ORDER-QTY       PIC 9(5).
        10  UNIT-COST       PIC 9(6)V99.

01  WS-PROCESSING-DATA.
    05  WS-INDEX            PIC 999.
    05  WS-TOTAL-COST       PIC 9(10)V99.
    05  WS-ITEM-TOTAL       PIC 9(8)V99.

PROCEDURE DIVISION.
CALCULATE-ORDER-TOTAL.
    MOVE ZERO TO WS-TOTAL-COST.
    
    PERFORM VARYING WS-INDEX FROM 1 BY 1
            UNTIL WS-INDEX > ITEM-COUNT
        COMPUTE WS-ITEM-TOTAL = ORDER-QTY (WS-INDEX) * 
                               UNIT-COST (WS-INDEX)
        ADD WS-ITEM-TOTAL TO WS-TOTAL-COST
        
        DISPLAY "ITEM " WS-INDEX ": " PRODUCT-NAME (WS-INDEX)
        DISPLAY "   QTY: " ORDER-QTY (WS-INDEX)
        DISPLAY "   COST: $" UNIT-COST (WS-INDEX)
        DISPLAY "   TOTAL: $" WS-ITEM-TOTAL
    END-PERFORM.
    
    DISPLAY "ORDER TOTAL: $" WS-TOTAL-COST.

Processing variable length arrays with calculations.

INDEXED BY Clause

Index Usage

01  PRODUCT-TABLE.
    05  PRODUCT-ENTRY       OCCURS 500 TIMES
                           INDEXED BY PROD-INDEX.
        10  PROD-CODE       PIC X(10).
        10  PROD-NAME       PIC X(25).
        10  PROD-PRICE      PIC 9(6)V99.
        10  PROD-QUANTITY   PIC 9(5).

01  CUSTOMER-TABLE.
    05  CUSTOMER-ENTRY      OCCURS 1000 TIMES
                           INDEXED BY CUST-INDEX.
        10  CUST-ID         PIC X(8).
        10  CUST-NAME       PIC X(30).
        10  CUST-BALANCE    PIC S9(8)V99.

PROCEDURE DIVISION.
SEARCH-PRODUCT-TABLE.
    SET PROD-INDEX TO 1.
    
    SEARCH PRODUCT-ENTRY
        AT END
            DISPLAY "PRODUCT NOT FOUND"
        WHEN PROD-CODE (PROD-INDEX) = WS-SEARCH-CODE
            DISPLAY "FOUND PRODUCT: " PROD-NAME (PROD-INDEX)
            DISPLAY "PRICE: $" PROD-PRICE (PROD-INDEX)
            DISPLAY "IN STOCK: " PROD-QUANTITY (PROD-INDEX)
    END-SEARCH.

Using indexes for efficient table searching.

Binary Search with SEARCH ALL

01  SORTED-EMPLOYEE-TABLE.
    05  EMPLOYEE-ENTRY      OCCURS 1000 TIMES
                           ASCENDING KEY IS EMP-ID
                           INDEXED BY EMP-INDEX.
        10  EMP-ID          PIC 9(6).
        10  EMP-NAME        PIC X(25).
        10  EMP-DEPT        PIC X(10).
        10  EMP-SALARY      PIC 9(6)V99.

PROCEDURE DIVISION.
BINARY-SEARCH-EMPLOYEE.
    SEARCH ALL EMPLOYEE-ENTRY
        AT END
            DISPLAY "EMPLOYEE ID NOT FOUND: " WS-SEARCH-ID
        WHEN EMP-ID (EMP-INDEX) = WS-SEARCH-ID
            DISPLAY "EMPLOYEE FOUND:"
            DISPLAY "  ID: " EMP-ID (EMP-INDEX)
            DISPLAY "  NAME: " EMP-NAME (EMP-INDEX)
            DISPLAY "  DEPT: " EMP-DEPT (EMP-INDEX)
            DISPLAY "  SALARY: $" EMP-SALARY (EMP-INDEX)
    END-SEARCH.

LOAD-EMPLOYEE-TABLE.
    *> Load data in ascending order by EMP-ID
    MOVE 100001 TO EMP-ID (1)
    MOVE "ALICE JOHNSON" TO EMP-NAME (1)
    MOVE "IT" TO EMP-DEPT (1)
    MOVE 65000.00 TO EMP-SALARY (1)
    
    MOVE 100002 TO EMP-ID (2)
    MOVE "BOB SMITH" TO EMP-NAME (2)
    MOVE "FINANCE" TO EMP-DEPT (2)
    MOVE 58000.00 TO EMP-SALARY (2).

Binary search on sorted tables using SEARCH ALL.

Table Processing Patterns

Table Initialization

01  MONTHLY-TOTALS.
    05  MONTH-DATA          OCCURS 12 TIMES.
        10  MONTH-NAME      PIC X(9).
        10  SALES-TOTAL     PIC 9(8)V99.
        10  TARGET-AMOUNT   PIC 9(8)V99.

01  WS-MONTH-NAMES.
    05  FILLER              PIC X(108) VALUE
        "JANUARY  FEBRUARY MARCH    APRIL    MAY      JUNE     " &
        "JULY     AUGUST   SEPTEMBEROCTOBER  NOVEMBER DECEMBER ".
    05  WS-MONTH-TABLE REDEFINES FILLER.
        10  WS-MONTH-ENTRY  OCCURS 12 TIMES PIC X(9).

PROCEDURE DIVISION.
INITIALIZE-MONTH-TABLE.
    PERFORM VARYING WS-INDEX FROM 1 BY 1 
            UNTIL WS-INDEX > 12
        MOVE WS-MONTH-ENTRY (WS-INDEX) TO MONTH-NAME (WS-INDEX)
        MOVE ZERO TO SALES-TOTAL (WS-INDEX)
        MOVE 100000.00 TO TARGET-AMOUNT (WS-INDEX)
    END-PERFORM.

DISPLAY-MONTH-TABLE.
    PERFORM VARYING WS-INDEX FROM 1 BY 1 
            UNTIL WS-INDEX > 12
        DISPLAY WS-INDEX ". " MONTH-NAME (WS-INDEX) 
                " - SALES: $" SALES-TOTAL (WS-INDEX)
                " TARGET: $" TARGET-AMOUNT (WS-INDEX)
    END-PERFORM.

Initializing tables with data and displaying contents.

Table Sorting and Processing

01  SALES-REPORT-TABLE.
    05  SALES-ENTRY         OCCURS 100 TIMES.
        10  SALESPERSON     PIC X(20).
        10  REGION          PIC X(10).
        10  SALES-AMOUNT    PIC 9(8)V99.
        10  COMMISSION      PIC 9(6)V99.

01  WS-SORT-VARIABLES.
    05  WS-INDEX            PIC 999.
    05  WS-INNER-INDEX      PIC 999.
    05  WS-ENTRY-COUNT      PIC 999.
    05  WS-TEMP-ENTRY.
        10  WS-TEMP-PERSON  PIC X(20).
        10  WS-TEMP-REGION  PIC X(10).
        10  WS-TEMP-SALES   PIC 9(8)V99.
        10  WS-TEMP-COMM    PIC 9(6)V99.

PROCEDURE DIVISION.
SORT-BY-SALES-AMOUNT.
    *> Bubble sort by sales amount (descending)
    PERFORM VARYING WS-INDEX FROM 1 BY 1 
            UNTIL WS-INDEX >= WS-ENTRY-COUNT
        PERFORM VARYING WS-INNER-INDEX FROM 1 BY 1 
                UNTIL WS-INNER-INDEX >= WS-ENTRY-COUNT
            IF SALES-AMOUNT (WS-INNER-INDEX) < 
               SALES-AMOUNT (WS-INNER-INDEX + 1)
                *> Swap entries
                MOVE SALES-ENTRY (WS-INNER-INDEX) TO WS-TEMP-ENTRY
                MOVE SALES-ENTRY (WS-INNER-INDEX + 1) TO 
                     SALES-ENTRY (WS-INNER-INDEX)
                MOVE WS-TEMP-ENTRY TO SALES-ENTRY (WS-INNER-INDEX + 1)
            END-IF
        END-PERFORM
    END-PERFORM.

CALCULATE-COMMISSIONS.
    PERFORM VARYING WS-INDEX FROM 1 BY 1 
            UNTIL WS-INDEX > WS-ENTRY-COUNT
        COMPUTE COMMISSION (WS-INDEX) = 
                SALES-AMOUNT (WS-INDEX) * 0.05
    END-PERFORM.

GENERATE-SALES-REPORT.
    DISPLAY "SALES PERFORMANCE REPORT"
    DISPLAY "========================"
    DISPLAY "RANK  SALESPERSON        REGION     SALES      COMMISSION"
    DISPLAY "----  ----------------   --------   ---------  ---------"
    
    PERFORM VARYING WS-INDEX FROM 1 BY 1 
            UNTIL WS-INDEX > WS-ENTRY-COUNT
        DISPLAY WS-INDEX ". " 
                SALESPERSON (WS-INDEX) " " 
                REGION (WS-INDEX) " $"
                SALES-AMOUNT (WS-INDEX) " $"
                COMMISSION (WS-INDEX)
    END-PERFORM.

Sorting table data and generating reports.

Advanced OCCURS Features

Complex Data Structures

01  COMPANY-STRUCTURE.
    05  DEPARTMENT-COUNT    PIC 99.
    05  DEPARTMENT-DATA     OCCURS 1 TO 20 TIMES
                           DEPENDING ON DEPARTMENT-COUNT
                           INDEXED BY DEPT-INDEX.
        10  DEPT-NAME       PIC X(20).
        10  DEPT-BUDGET     PIC 9(8)V99.
        10  EMPLOYEE-COUNT  PIC 999.
        10  EMPLOYEE-DATA   OCCURS 1 TO 50 TIMES
                           DEPENDING ON EMPLOYEE-COUNT
                           INDEXED BY EMP-INDEX.
            15  EMP-NUM     PIC 9(6).
            15  EMP-NAME    PIC X(25).
            15  EMP-TITLE   PIC X(20).
            15  EMP-SALARY  PIC 9(6)V99.

PROCEDURE DIVISION.
PROCESS-COMPANY-DATA.
    PERFORM VARYING DEPT-INDEX FROM 1 BY 1 
            UNTIL DEPT-INDEX > DEPARTMENT-COUNT
        
        DISPLAY "DEPARTMENT: " DEPT-NAME (DEPT-INDEX)
        DISPLAY "BUDGET: $" DEPT-BUDGET (DEPT-INDEX)
        DISPLAY "EMPLOYEES:"
        
        PERFORM VARYING EMP-INDEX FROM 1 BY 1 
                UNTIL EMP-INDEX > EMPLOYEE-COUNT (DEPT-INDEX)
            DISPLAY "  " EMP-NUM (DEPT-INDEX, EMP-INDEX) 
                    " - " EMP-NAME (DEPT-INDEX, EMP-INDEX)
                    " (" EMP-TITLE (DEPT-INDEX, EMP-INDEX) ")"
                    " $" EMP-SALARY (DEPT-INDEX, EMP-INDEX)
        END-PERFORM
        
        DISPLAY SPACES
    END-PERFORM.

Nested variable-length tables with complex processing.

Table Statistics and Analysis

01  STATISTICAL-DATA.
    05  DATA-COUNT          PIC 999.
    05  DATA-VALUES         OCCURS 1 TO 500 TIMES
                           DEPENDING ON DATA-COUNT.
        10  VALUE-AMOUNT    PIC S9(6)V99.

01  WS-STATISTICS.
    05  WS-SUM              PIC S9(10)V99.
    05  WS-AVERAGE          PIC S9(8)V99.
    05  WS-MINIMUM          PIC S9(6)V99.
    05  WS-MAXIMUM          PIC S9(6)V99.
    05  WS-COUNT            PIC 999.
    05  WS-INDEX            PIC 999.

PROCEDURE DIVISION.
CALCULATE-STATISTICS.
    MOVE ZERO TO WS-SUM.
    MOVE 999999.99 TO WS-MINIMUM.
    MOVE -999999.99 TO WS-MAXIMUM.
    
    PERFORM VARYING WS-INDEX FROM 1 BY 1 
            UNTIL WS-INDEX > DATA-COUNT
        
        ADD VALUE-AMOUNT (WS-INDEX) TO WS-SUM
        
        IF VALUE-AMOUNT (WS-INDEX) < WS-MINIMUM
            MOVE VALUE-AMOUNT (WS-INDEX) TO WS-MINIMUM
        END-IF
        
        IF VALUE-AMOUNT (WS-INDEX) > WS-MAXIMUM
            MOVE VALUE-AMOUNT (WS-INDEX) TO WS-MAXIMUM
        END-IF
    END-PERFORM.
    
    COMPUTE WS-AVERAGE = WS-SUM / DATA-COUNT.
    
    DISPLAY "STATISTICAL ANALYSIS:"
    DISPLAY "  COUNT: " DATA-COUNT
    DISPLAY "  SUM: $" WS-SUM
    DISPLAY "  AVERAGE: $" WS-AVERAGE
    DISPLAY "  MINIMUM: $" WS-MINIMUM
    DISPLAY "  MAXIMUM: $" WS-MAXIMUM.

Statistical analysis of table data.

Performance Considerations

  • Index vs Subscript: Use indexes (INDEXED BY) for better performance than subscripts
  • SEARCH ALL: Use binary search on sorted tables for O(log n) performance
  • Table Size: Consider memory usage with large tables or OCCURS DEPENDING ON
  • Initialization: Initialize tables efficiently to avoid performance bottlenecks

Common Patterns

PatternUse CaseExample
Fixed OCCURSKnown table sizeOCCURS 12 TIMES
DEPENDING ONVariable table sizeOCCURS 1 TO 100 DEPENDING ON
INDEXED BYSearch operationsINDEXED BY TABLE-INDEX
KEY clauseSorted tablesASCENDING KEY IS DATA-FIELD

Best Practices

  • Use descriptive names for table elements and indexes
  • Validate array bounds before accessing table elements
  • Initialize tables properly before use
  • Use SEARCH ALL for sorted tables when possible
  • Consider memory implications of large variable tables

Related Concepts

SEARCH Statement

Linear search through table elements

SEARCH ALL

Binary search on sorted tables

SET Statement

Index manipulation and initialization

PERFORM VARYING

Loop control for table processing