Relative Files

COBOL COBOL 2014 (ISO/IEC 1989:2014), built with GnuCOBOL 3.x Β· βœ“ verified by execution on 2026-08-16

While Indexed files allow you to look up records by alphanumeric values (like a Customer ID or Last Name), Relative files are much simpler. They act just like an array on disk.

In a relative file, every record is stored in a numbered β€œslot” starting from 1. This number is called the Relative Record Number (RRN). Because the operating system knows exactly how wide each record is, it can instantly calculate the byte offset on the disk to fetch slot #500 without having to maintain a complex index or read records 1 through 499.

Relative File Layout RRN 1 "Alice" RRN 2 "Bob" RRN 3 (Empty) RRN 4 "Dave"

The RELATIVE KEY

There is a major structural difference between an indexed file and a relative file. In an indexed file, the RECORD KEY is defined inside the FD structure because the key is part of the data on disk.

For a relative file, the RELATIVE KEY is just a slot number. It is not part of the data written to disk. Therefore, the RELATIVE KEY MUST be defined in your WORKING-STORAGE SECTION as an unsigned integer.

Let’s write a record directly into slot 5:

cobol βœ“ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. WR-REL.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT REL-FILE ASSIGN TO "rel.dat"
               ORGANIZATION IS RELATIVE
               ACCESS MODE IS RANDOM
               RELATIVE KEY IS WS-RRN.
       DATA DIVISION.
       FILE SECTION.
       FD REL-FILE.
       01 REL-REC PIC X(10).
       WORKING-STORAGE SECTION.
       01 WS-RRN PIC 9(4).
       PROCEDURE DIVISION.
           OPEN OUTPUT REL-FILE
           MOVE 5 TO WS-RRN
           MOVE "SLOT 5" TO REL-REC
           WRITE REL-REC
             INVALID KEY DISPLAY "ERROR"
             NOT INVALID KEY DISPLAY "WROTE 5"
           END-WRITE
           CLOSE REL-FILE
           STOP RUN.
Output
WROTE 5

Because we wrote directly to RRN 5, slots 1 through 4 are technically empty. If we attempt to read slot 2, COBOL will trigger an INVALID KEY condition because that slot was never populated.

Reading Randomly

To fetch a record, you simply move the desired slot number into your RELATIVE KEY variable and issue a READ:

cobol βœ“ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. RD-REL.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT R-FILE ASSIGN TO "rel2.dat"
               ORGANIZATION IS RELATIVE
               ACCESS MODE IS RANDOM
               RELATIVE KEY IS W-RRN.
       DATA DIVISION.
       FILE SECTION.
       FD R-FILE.
       01 R-REC PIC X(10).
       WORKING-STORAGE SECTION.
       01 W-RRN PIC 9(4).
       PROCEDURE DIVISION.
           OPEN OUTPUT R-FILE
           MOVE 3 TO W-RRN. WRITE R-REC FROM "DATA 3".
           CLOSE R-FILE
           OPEN INPUT R-FILE
           MOVE 3 TO W-RRN
           READ R-FILE
             INVALID KEY DISPLAY "MISSING"
             NOT INVALID KEY DISPLAY R-REC
           END-READ
           CLOSE R-FILE
           STOP RUN.
Output
DATA 3    

Sequential Writing

If you set ACCESS MODE IS SEQUENTIAL and perform WRITE statements, COBOL automatically places the records in consecutive slots (1, 2, 3…). Even better, COBOL automatically updates your RELATIVE KEY variable to reflect the assigned RRN!

cobol βœ“ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. SEQ-REL.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT REL-FILE ASSIGN TO "rel3.dat"
               ORGANIZATION IS RELATIVE
               ACCESS MODE IS SEQUENTIAL
               RELATIVE KEY IS WS-RRN.
       DATA DIVISION.
       FILE SECTION.
       FD REL-FILE.
       01 REL-REC PIC X(5).
       WORKING-STORAGE SECTION.
       01 WS-RRN PIC 9(4).
       PROCEDURE DIVISION.
           OPEN OUTPUT REL-FILE
           WRITE REL-REC FROM "ONE".
           DISPLAY "RRN=" WS-RRN.
           WRITE REL-REC FROM "TWO".
           DISPLAY "RRN=" WS-RRN.
           CLOSE REL-FILE
           STOP RUN.
Output
RRN=0001
RRN=0002

Deleting Records

When a relative file is opened in I-O mode (which allows both reading and writing), you can free a slot using the DELETE verb. This physically removes the record from the slot, making it empty again without shifting the positions of any other records.

Mental Model Verification

Let’s test a common misconception about the separation between the file buffer (FD) and the RELATIVE KEY. Look at this pointer simulation. Notice that altering the slot variable does not alter the data buffer!

Predict the output cobol

Read the code. What exactly will it print? Commit to an answer before you look.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. REL-PTR.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 WS-RRN PIC 9 VALUE 1.
       01 FD-BUF PIC X(4) VALUE "AAAA".
       PROCEDURE DIVISION.
           MOVE 4 TO WS-RRN.
           DISPLAY FD-BUF "-" WS-RRN.
           STOP RUN.
Output
AAAA-4

Because the RELATIVE KEY lives in Working-Storage separately from the FD, moving a value to it only prepares the file pointer for the next operation. It never alters the data record buffer itself.

Check yourself

Unlike an Indexed file where the Record Key is stored inside the data record itself, where MUST the Relative Key for a relative file be defined?

Reveal answer

In WORKING-STORAGE β€” The Relative Key represents the slot number (RRN). It is not part of the data written to disk, so it must be defined separately in WORKING-STORAGE.

What happens if you try to READ a Relative Record Number (RRN) that has never been written to?

Reveal answer

It triggers an INVALID KEY condition β€” Reading an empty slot results in an INVALID KEY condition, just like trying to read a non-existent key in an indexed file.

If you open a relative file with ACCESS MODE IS SEQUENTIAL and perform WRITE statements, how is the RELATIVE KEY affected?

Reveal answer

COBOL automatically populates the RELATIVE KEY with the slot number assigned to the new record. β€” When writing sequentially to a relative file, the system sequentially assigns the next available slot and updates your RELATIVE KEY variable automatically.

Challenges

🐞 Bug Hunt +50 XP

Bug hunt: The programmer copied some code from an Indexed File program and tried to adapt it for a Relative File, but it won't compile! The compiler complains about the RELATIVE KEY. Fix the code by moving the RELATIVE KEY definition out of the FD record and into the correct section.

This code runs. It just does the wrong thing. Read it, find the defect, fix it β€” the tests below decide when you are right.

cobol βœ“ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real β€” it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 β€” expects "SUCCESS\n"
Need a hint? (βˆ’25% XP)

The RELATIVE KEY cannot be part of the FD record. Move WS-RRN to WORKING-STORAGE.

Show solution (0 XP)
IDENTIFICATION DIVISION.
PROGRAM-ID. BugHunt.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT REL-FILE ASSIGN TO "test.dat"
        ORGANIZATION IS RELATIVE
        ACCESS MODE IS RANDOM
        RELATIVE KEY IS WS-RRN.
DATA DIVISION.
FILE SECTION.
FD REL-FILE.
01 REL-REC.
   05 NAME-FIELD PIC X(10).
WORKING-STORAGE SECTION.
01 WS-RRN PIC 9(4).
PROCEDURE DIVISION.
    DISPLAY "SUCCESS"
    STOP RUN.

Challenge 2 +50 XP

What data type must a `RELATIVE KEY` be?

cobol βœ“ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real β€” it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 β€” expects "INTEGER"
Need a hint? (βˆ’25% XP)

Think numbers.

Show solution (0 XP)
       IDENTIFICATION DIVISION.
       PROGRAM-ID. CHAL2.
       PROCEDURE DIVISION.
           DISPLAY "INTEGER".
           STOP RUN.