MainframeMaster
MainframeMaster

COBOL Tutorial

Progress0 of 0 lessons

COBOL Table Handling

Table handling in COBOL involves working with arrays (called tables) that contain multiple occurrences of the same data format. Tables are defined using the OCCURS clause, accessed using subscripts or indices, and searched using SEARCH or SEARCH ALL statements. Understanding table handling is essential for processing collections of data, implementing lookup tables, managing lists, and working with structured data sets in mainframe COBOL programs.

What is a Table in COBOL?

A table (array) in COBOL is a data structure containing multiple occurrences of the same format:

  • Multiple elements: Contains many items of the same type
  • Indexed access: Elements accessed by position (subscript or index)
  • Efficient storage: Stores related data in a structured way
  • Processing capability: Can be processed in loops, searched, and sorted

Tables are useful for storing lists of customers, products, transaction records, lookup values, and any collection of related data.

Defining Tables with OCCURS

The OCCURS clause defines a table by specifying how many times a data item repeats:

Basic OCCURS Syntax

cobol
1
2
3
level-number data-name OCCURS integer TIMES [INDEXED BY index-name-1 [index-name-2 ...]].

Rules for OCCURS:

  • Level 05 or below: OCCURS can only be used at level 05 or lower
  • Not with 01, 66, 77, 88: Cannot use OCCURS with these special levels
  • Fixed or variable size: Can specify fixed size or use DEPENDING ON for variable size
  • Indexed access: Optional INDEXED BY for efficient access

Example: Simple Table Definition

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
WORKING-STORAGE SECTION. 01 CUSTOMER-TABLE. 05 CUSTOMER-ENTRY OCCURS 100 TIMES INDEXED BY CUST-INDEX. 10 CUSTOMER-ID PIC 9(5). 10 CUSTOMER-NAME PIC X(30). 10 CUSTOMER-BALANCE PIC 9(8)V99. PROCEDURE DIVISION. MAIN-PARA. *> Access first customer SET CUST-INDEX TO 1 MOVE 12345 TO CUSTOMER-ID(CUST-INDEX) MOVE 'JOHN SMITH' TO CUSTOMER-NAME(CUST-INDEX) MOVE 1000.50 TO CUSTOMER-BALANCE(CUST-INDEX) *> Access fifth customer SET CUST-INDEX TO 5 DISPLAY "Customer 5: " CUSTOMER-NAME(CUST-INDEX) STOP RUN.

This defines a table of 100 customer entries, each containing ID, name, and balance. The INDEXED BY clause creates an index for efficient access.

Accessing Table Elements

Table elements can be accessed using subscripts or indices:

Using Subscripts

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
WORKING-STORAGE SECTION. 01 PRODUCT-TABLE. 05 PRODUCT-NAME OCCURS 50 TIMES PIC X(20). 01 SUBSCRIPT PIC 9(3) VALUE 1. PROCEDURE DIVISION. MAIN-PARA. *> Access using subscript MOVE 1 TO SUBSCRIPT MOVE 'WIDGET A' TO PRODUCT-NAME(SUBSCRIPT) ADD 1 TO SUBSCRIPT MOVE 'WIDGET B' TO PRODUCT-NAME(SUBSCRIPT) *> Display element MOVE 1 TO SUBSCRIPT DISPLAY "Product 1: " PRODUCT-NAME(SUBSCRIPT) STOP RUN.

Subscripts are numeric data items (PIC 9) used to access table elements. They use 1-based indexing (first element is at position 1).

Using Indices

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
WORKING-STORAGE SECTION. 01 PRODUCT-TABLE. 05 PRODUCT-NAME OCCURS 50 TIMES INDEXED BY PROD-INDEX PIC X(20). PROCEDURE DIVISION. MAIN-PARA. *> Access using index SET PROD-INDEX TO 1 MOVE 'WIDGET A' TO PRODUCT-NAME(PROD-INDEX) SET PROD-INDEX UP BY 1 MOVE 'WIDGET B' TO PRODUCT-NAME(PROD-INDEX) *> Display element SET PROD-INDEX TO 1 DISPLAY "Product 1: " PRODUCT-NAME(PROD-INDEX) STOP RUN.

Indices are special data items defined with INDEXED BY. They use SET statements (not MOVE) and are more efficient than subscripts for large tables.

Subscript vs Index Comparison
AspectSubscriptIndex
DefinitionRegular numeric data item (PIC 9)Defined with INDEXED BY clause
AssignmentMOVE value TO subscriptSET index TO value
IncrementADD 1 TO subscriptSET index UP BY 1
EfficiencyLess efficient for large tablesMore efficient, optimized by compiler
Required forGeneral table accessSEARCH and SEARCH ALL statements
OperationsCan use arithmetic (ADD, SUBTRACT)Use SET statements only

Processing Tables with Loops

Tables are typically processed using PERFORM loops:

Example: Processing All Table Elements

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
WORKING-STORAGE SECTION. 01 SALES-TABLE. 05 SALES-AMOUNT OCCURS 100 TIMES INDEXED BY SALES-INDEX PIC 9(8)V99. 01 TOTAL-SALES PIC 9(10)V99 VALUE ZERO. 01 TABLE-SIZE PIC 9(3) VALUE 100. PROCEDURE DIVISION. MAIN-PARA. *> Process all table elements PERFORM VARYING SALES-INDEX FROM 1 BY 1 UNTIL SALES-INDEX > TABLE-SIZE ADD SALES-AMOUNT(SALES-INDEX) TO TOTAL-SALES END-PERFORM DISPLAY "Total Sales: " TOTAL-SALES STOP RUN.

This loop processes all elements in the table, summing the sales amounts.

Example: Initializing a Table

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
WORKING-STORAGE SECTION. 01 COUNTER-TABLE. 05 COUNTER-VALUE OCCURS 50 TIMES INDEXED BY CTR-INDEX PIC 9(5) VALUE ZERO. PROCEDURE DIVISION. MAIN-PARA. *> Initialize all elements to zero INITIALIZE COUNTER-TABLE *> Or initialize with specific values PERFORM VARYING CTR-INDEX FROM 1 BY 1 UNTIL CTR-INDEX > 50 MOVE CTR-INDEX TO COUNTER-VALUE(CTR-INDEX) END-PERFORM STOP RUN.

SEARCH Statement

SEARCH performs a linear (sequential) search through a table:

SEARCH Syntax

cobol
1
2
3
4
5
6
7
SET index TO starting-position SEARCH table-name [AT END imperative-statement] [WHEN condition-1 imperative-statement-1] [WHEN condition-2 imperative-statement-2] ... END-SEARCH.

SEARCH requires:

  • INDEXED BY clause: Table must have an index defined
  • SET index first: Set starting position before SEARCH
  • WHEN conditions: Conditions to test for each element
  • AT END: Executes if no match found

Example: Searching for a Customer

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
WORKING-STORAGE SECTION. 01 CUSTOMER-TABLE. 05 CUSTOMER-ENTRY OCCURS 100 TIMES INDEXED BY CUST-INDEX. 10 CUSTOMER-ID PIC 9(5). 10 CUSTOMER-NAME PIC X(30). 01 SEARCH-ID PIC 9(5) VALUE 12345. 01 FOUND-FLAG PIC X VALUE 'N'. 88 CUSTOMER-FOUND VALUE 'Y'. PROCEDURE DIVISION. MAIN-PARA. SET CUST-INDEX TO 1 SEARCH CUSTOMER-ENTRY AT END DISPLAY "Customer not found" MOVE 'N' TO FOUND-FLAG WHEN CUSTOMER-ID(CUST-INDEX) = SEARCH-ID DISPLAY "Customer found: " CUSTOMER-NAME(CUST-INDEX) MOVE 'Y' TO FOUND-FLAG END-SEARCH IF CUSTOMER-FOUND *> Process found customer END-IF STOP RUN.

SEARCH starts from the index position and searches sequentially until it finds a match or reaches the end of the table.

SEARCH ALL Statement

SEARCH ALL performs a binary search on a sorted table:

SEARCH ALL Syntax

cobol
1
2
3
4
SEARCH ALL table-name [AT END imperative-statement] [WHEN condition imperative-statement] END-SEARCH.

SEARCH ALL requirements:

  • Sorted table: Table must be sorted in ascending order on the search key
  • INDEXED BY clause: Table must have an index
  • Binary search: Uses efficient binary search algorithm
  • Faster: Much faster than SEARCH for large tables

Example: Binary Search

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
WORKING-STORAGE SECTION. 01 PRODUCT-TABLE. 05 PRODUCT-ENTRY OCCURS 1000 TIMES INDEXED BY PROD-INDEX. 10 PRODUCT-CODE PIC 9(5). 10 PRODUCT-NAME PIC X(30). 10 PRODUCT-PRICE PIC 9(6)V99. *> Table must be sorted by PRODUCT-CODE 01 SEARCH-CODE PIC 9(5) VALUE 54321. PROCEDURE DIVISION. MAIN-PARA. SEARCH ALL PRODUCT-ENTRY AT END DISPLAY "Product not found" WHEN PRODUCT-CODE(PROD-INDEX) = SEARCH-CODE DISPLAY "Product: " PRODUCT-NAME(PROD-INDEX) DISPLAY "Price: " PRODUCT-PRICE(PROD-INDEX) END-SEARCH STOP RUN.

SEARCH ALL is much faster than SEARCH for large sorted tables because it uses binary search, which eliminates half the remaining elements with each comparison.

SEARCH vs SEARCH ALL Comparison
AspectSEARCHSEARCH ALL
Search typeLinear (sequential)Binary
Table requirementCan be unsortedMust be sorted
SpeedSlower for large tablesFaster for large tables
Starting positionSet index before SEARCHNot needed (searches entire table)
Use whenUnsorted tables or finding first matchLarge sorted tables
EfficiencyO(n) - checks each elementO(log n) - eliminates half each time

Dynamic Tables

Dynamic tables allow variable sizes at runtime using DEPENDING ON:

Dynamic Table Syntax

cobol
1
2
3
4
level-number data-name OCCURS 1 TO max-size TIMES DEPENDING ON size-field [INDEXED BY index-name].

Example: Dynamic Table

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
WORKING-STORAGE SECTION. 01 TABLE-SIZE PIC 9(4) VALUE 100. 01 CUSTOMER-TABLE. 05 CUSTOMER-ENTRY OCCURS 1 TO 1000 TIMES DEPENDING ON TABLE-SIZE INDEXED BY CUST-INDEX. 10 CUSTOMER-ID PIC 9(5). 10 CUSTOMER-NAME PIC X(30). PROCEDURE DIVISION. MAIN-PARA. *> Set table size MOVE 50 TO TABLE-SIZE *> Process only the active portion PERFORM VARYING CUST-INDEX FROM 1 BY 1 UNTIL CUST-INDEX > TABLE-SIZE *> Process CUSTOMER-ENTRY(CUST-INDEX) END-PERFORM *> Resize table ADD 25 TO TABLE-SIZE STOP RUN.

Dynamic tables provide flexibility when the number of elements is not known at compile time. The size-field determines how many elements are actually used.

Multi-Dimensional Tables

COBOL supports multi-dimensional tables (tables of tables):

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
WORKING-STORAGE SECTION. 01 SALES-TABLE. 05 REGION-ENTRY OCCURS 10 TIMES INDEXED BY REGION-INDEX. 10 REGION-NAME PIC X(20). 10 MONTH-SALES OCCURS 12 TIMES INDEXED BY MONTH-INDEX PIC 9(8)V99. PROCEDURE DIVISION. MAIN-PARA. *> Access sales for region 3, month 6 SET REGION-INDEX TO 3 SET MONTH-INDEX TO 6 DISPLAY "Sales: " MONTH-SALES(REGION-INDEX, MONTH-INDEX) STOP RUN.

This creates a two-dimensional table: 10 regions, each with 12 months of sales data.

Best Practices for Table Handling

Follow these best practices:

  • Use INDEXED BY for searches: Always define indexes when you'll use SEARCH or SEARCH ALL
  • Validate subscripts/indices: Check that subscripts/indices are within valid range before accessing
  • Initialize tables properly: Use INITIALIZE or loops to set initial values
  • Sort before SEARCH ALL: Ensure tables are sorted when using SEARCH ALL
  • Use appropriate search: Use SEARCH for unsorted tables, SEARCH ALL for large sorted tables
  • Document table structure: Comment table definitions to explain purpose and usage
  • Handle empty tables: Check table size before processing to avoid errors
  • Use meaningful names: Name tables, indices, and subscripts descriptively
  • Consider performance: Use indices for large tables, SEARCH ALL for sorted large tables
  • Test boundary conditions: Test with empty tables, single element, and maximum size

Common Table Patterns

Pattern 1: Lookup Table

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
*> State code lookup table 01 STATE-TABLE. 05 STATE-ENTRY OCCURS 50 TIMES INDEXED BY STATE-INDEX. 10 STATE-CODE PIC X(2). 10 STATE-NAME PIC X(20). *> Search for state name by code SET STATE-INDEX TO 1 SEARCH STATE-ENTRY WHEN STATE-CODE(STATE-INDEX) = SEARCH-CODE MOVE STATE-NAME(STATE-INDEX) TO RESULT-NAME END-SEARCH

Pattern 2: Accumulator Table

cobol
1
2
3
4
5
6
7
8
9
*> Accumulate totals by category 01 CATEGORY-TOTALS. 05 CATEGORY-AMOUNT OCCURS 20 TIMES INDEXED BY CAT-INDEX PIC 9(10)V99 VALUE ZERO. *> Add to category total SET CAT-INDEX TO CATEGORY-NUMBER ADD TRANSACTION-AMOUNT TO CATEGORY-AMOUNT(CAT-INDEX)

Pattern 3: Processing All Elements

cobol
1
2
3
4
5
*> Process all table elements PERFORM VARYING TABLE-INDEX FROM 1 BY 1 UNTIL TABLE-INDEX > TABLE-SIZE *> Process ELEMENT(TABLE-INDEX) END-PERFORM

Explain Like I'm 5: Table Handling

Think of a table like a row of mailboxes:

  • OCCURS is like having many mailboxes in a row - you decide how many mailboxes you need
  • Subscript/Index is like the mailbox number - you use it to find the right mailbox
  • SEARCH is like checking each mailbox one by one until you find what you're looking for
  • SEARCH ALL is like having mailboxes in order and using a smart way to find things faster
  • Dynamic table is like having a row of mailboxes where you can use as many as you need, not all of them

So table handling is like organizing and finding things in a row of mailboxes - you put things in numbered boxes and use the numbers to find them later!

Practice Exercises

Complete these exercises to reinforce your understanding:

Exercise 1: Basic Table

Create a table of 10 product names. Initialize all elements, then display each product name using a PERFORM loop.

Exercise 2: Table Search

Create a customer table with ID and name. Use SEARCH to find a customer by ID and display their name.

Exercise 3: SEARCH ALL

Create a sorted product table (sorted by product code). Use SEARCH ALL to find a product by code and display its price.

Exercise 4: Dynamic Table

Create a dynamic table that can hold 1 to 100 items. Read a number of items, set the table size, then process only that many items.

Exercise 5: Multi-Dimensional Table

Create a two-dimensional table representing sales by region (5 regions) and month (12 months). Calculate and display total sales for each region.

Test Your Knowledge

1. What clause defines a table in COBOL?

  • TABLE clause
  • OCCURS clause
  • ARRAY clause
  • INDEX clause

2. What is required for SEARCH and SEARCH ALL statements?

  • A subscript
  • An INDEXED BY clause
  • A sorted table only
  • A fixed-size table

3. What is the difference between SEARCH and SEARCH ALL?

  • There is no difference
  • SEARCH is linear, SEARCH ALL is binary and requires sorted table
  • SEARCH ALL is linear, SEARCH is binary
  • SEARCH only works with numeric tables

4. How do you set an index value in COBOL?

  • MOVE value TO index
  • SET index TO value
  • ADD value TO index
  • COMPUTE index = value

5. What makes a table dynamic in COBOL?

  • Using OCCURS with variable name
  • Using OCCURS with DEPENDING ON
  • Using INDEXED BY
  • Using SEARCH ALL

6. What level can OCCURS be used at?

  • Level 01 only
  • Level 05 or below
  • Any level
  • Level 77 only

Related Concepts

Related Pages