> "Sort is the unsung hero of batch processing. Every night, trillions of dollars move through sorted transaction files — and if the sort fails, the bank doesn't open in the morning." — Maria Chen, reflecting on her first production sort ABEND
In This Chapter
- 15.1 Introduction: Why Sorting Matters
- 15.2 The SORT Verb: Fundamentals
- 15.3 Simple Sorting with USING and GIVING
- 15.4 INPUT PROCEDURE: Filtering and Transforming Before Sort
- 15.5 OUTPUT PROCEDURE: Processing After Sort
- 15.6 Combining INPUT and OUTPUT PROCEDUREs
- 15.7 The MERGE Verb
- 15.8 Sort Error Handling — Defensive Programming
- 15.9 External Sort Utilities: DFSORT and SyncSort
- 15.10 Advanced Sort Patterns
- 15.11 MedClaim Case Study: Sorting Claims for Batch Adjudication
- 15.12 Sort Performance Considerations
- 15.13 Sort and Merge Restrictions
- 15.14 GnuCOBOL Sort Considerations
- 15.15 Common Sort Patterns in Practice
- 15.16 Putting It All Together: A Production Sort Program Checklist
- 15.17 Multi-Key Sort Strategies
- 15.18 Sort Performance Benchmarking
- 15.19 External Sort Integration: COBOL and JCL Working Together
- 15.20 Chapter Summary
- Key Terms Introduced in This Chapter
Chapter 15: Sort and Merge
"Sort is the unsung hero of batch processing. Every night, trillions of dollars move through sorted transaction files — and if the sort fails, the bank doesn't open in the morning." — Maria Chen, reflecting on her first production sort ABEND
15.1 Introduction: Why Sorting Matters
In the world of mainframe batch processing, sorting is not merely a convenience — it is a foundational operation. Consider the nightly batch cycle at GlobalBank: 2.3 million transactions must be sorted by account number before the balance update program can process them sequentially against the account master file. Without that sort step, the entire nightly cycle grinds to a halt.
Sorting in COBOL serves several critical purposes:
- Sequential file matching: When two files must be processed together (matched by key), both files must be in the same key sequence.
- Report generation: Reports almost always require data in a specific order — by region, by date, by customer, by amount.
- Deduplication: Sorting brings duplicate records together, making them easy to detect and eliminate.
- Performance optimization: Many batch algorithms assume sorted input. A merge-based update against a master file, for instance, requires both files to be sorted on the same key.
- Regulatory compliance: Audit trails often require records in chronological order, and regulatory reports demand specific sort sequences.
COBOL provides two built-in verbs for ordering data: SORT and MERGE. These verbs invoke the system's sort utility (such as IBM's DFSORT or Syncsort's SyncSort on z/OS) through a high-level, declarative interface. You describe what you want sorted and how — the runtime handles the rest.
💡 Why Not Just Use JCL SORT? You can absolutely sort files outside of COBOL using JCL and a sort utility directly. In fact, for simple sorts with no data transformation, that is often the preferred approach. But when you need to filter, transform, or validate records during the sort — that is where COBOL's SORT verb with INPUT and OUTPUT PROCEDUREs shines. It gives you the power of a high-performance sort engine combined with the full expressiveness of COBOL's data manipulation capabilities.
In this chapter, we will explore the SORT and MERGE verbs in depth, from simple single-key sorts through complex multi-key operations with filtering and transformation. We will examine both the USING/GIVING shorthand and the more powerful INPUT/OUTPUT PROCEDURE approach. Along the way, we will see how GlobalBank sorts its daily transaction file and how MedClaim prepares claims for batch adjudication.
15.2 The SORT Verb: Fundamentals
The SORT verb arranges records in a specified order based on one or more key fields. At its simplest, a SORT reads records from an input file, sorts them, and writes them to an output file. Let us begin with the basic syntax.
15.2.1 Basic SORT Syntax
SORT sort-file-name
ON {ASCENDING | DESCENDING} KEY data-name-1 [data-name-2 ...]
[ON {ASCENDING | DESCENDING} KEY data-name-3 ...]
[WITH DUPLICATES IN ORDER]
[COLLATING SEQUENCE IS alphabet-name]
{USING input-file-name [input-file-name-2 ...]}
{GIVING output-file-name [output-file-name-2 ...]}
Several elements require explanation:
- sort-file-name: This is not a regular file. It is a special work file declared with an SD (Sort Description) entry in the FILE SECTION. The system uses this as temporary workspace during the sort.
- ASCENDING/DESCENDING KEY: Specifies the sort order and identifies which fields to sort on. You can specify multiple KEY clauses for multi-level sorting.
- WITH DUPLICATES IN ORDER: Guarantees that records with equal key values retain their original input order (a stable sort). Without this clause, the relative order of equal-key records is implementation-defined.
- COLLATING SEQUENCE: Overrides the default character comparison sequence (EBCDIC on mainframes, ASCII on open systems).
- USING: Names the input file(s) — the sort reads from these automatically.
- GIVING: Names the output file(s) — the sort writes results here automatically.
15.2.2 The Sort Description (SD) Entry
Before you can sort, you must declare a sort work file. This uses the SD (Sort Description) level indicator instead of the usual FD:
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SORT-WORK-FILE ASSIGN TO SORTWK01.
SELECT INPUT-FILE ASSIGN TO INFILE.
SELECT OUTPUT-FILE ASSIGN TO OUTFILE.
DATA DIVISION.
FILE SECTION.
SD SORT-WORK-FILE.
01 SORT-RECORD.
05 SR-ACCOUNT-NUM PIC X(10).
05 SR-TRANS-DATE PIC X(08).
05 SR-TRANS-TYPE PIC X(01).
05 SR-AMOUNT PIC S9(09)V99.
05 SR-DESCRIPTION PIC X(30).
05 FILLER PIC X(40).
FD INPUT-FILE.
01 INPUT-RECORD PIC X(100).
FD OUTPUT-FILE.
01 OUTPUT-RECORD PIC X(100).
⚠️ Critical Rule: You never explicitly OPEN or CLOSE a sort work file (the SD file). The SORT verb manages its lifecycle automatically. Attempting to OPEN an SD file will cause a compilation error.
The SD entry does not specify BLOCK CONTAINS, RECORD CONTAINS, or LABEL RECORDS clauses (though RECORD CONTAINS is permitted on some compilers). The sort utility manages its own blocking and buffering.
15.2.3 JCL Considerations
On z/OS, the sort work file requires sort work datasets defined in JCL:
//SORTWK01 DD DSN=&&SORTWK1,SPACE=(CYL,(10,5)),UNIT=SYSDA
//SORTWK02 DD DSN=&&SORTWK2,SPACE=(CYL,(10,5)),UNIT=SYSDA
//SORTWK03 DD DSN=&&SORTWK3,SPACE=(CYL,(10,5)),UNIT=SYSDA
📊 Performance Note: The number and size of sort work datasets directly affect sort performance. A general rule of thumb is to allocate sort work space equal to at least twice the size of the input data. For very large sorts, more work datasets allow the sort utility to parallelize its I/O.
15.3 Simple Sorting with USING and GIVING
The USING and GIVING phrases provide the simplest form of sorting. The SORT verb automatically opens the input and output files, reads all records, sorts them, writes the sorted records, and closes the files.
15.3.1 Single-Key Ascending Sort
Here is a complete program that sorts a transaction file by account number:
IDENTIFICATION DIVISION.
PROGRAM-ID. SORT-SIMPLE.
*================================================================
* Program: SORT-SIMPLE
* Purpose: Sort transaction file by account number (ascending)
* Author: Student Mainframe Lab - Chapter 15
*================================================================
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SORT-FILE ASSIGN TO SORTWK01.
SELECT TRANS-IN ASSIGN TO INFILE.
SELECT TRANS-OUT ASSIGN TO OUTFILE.
DATA DIVISION.
FILE SECTION.
SD SORT-FILE.
01 SORT-REC.
05 SR-ACCT-NUM PIC X(10).
05 SR-TRANS-DATE PIC 9(08).
05 SR-TRANS-TYPE PIC X(01).
88 SR-DEPOSIT VALUE 'D'.
88 SR-WITHDRAWAL VALUE 'W'.
88 SR-TRANSFER VALUE 'T'.
05 SR-AMOUNT PIC S9(09)V99 COMP-3.
05 SR-DESC PIC X(30).
05 FILLER PIC X(34).
FD TRANS-IN
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 TRANS-IN-REC PIC X(90).
FD TRANS-OUT
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 TRANS-OUT-REC PIC X(90).
PROCEDURE DIVISION.
0000-MAIN.
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
USING TRANS-IN
GIVING TRANS-OUT
STOP RUN.
That is the entire program. The SORT verb handles all file I/O. Notice:
- No OPEN or CLOSE statements for any of the three files
- No READ or WRITE statements
- No PERFORM loops
- The PROCEDURE DIVISION is just two statements: SORT and STOP RUN
✅ Best Practice: For simple sorts that require no filtering or transformation, the USING/GIVING approach is preferred. It is concise, clear, and often generates more efficient sort utility calls because the sort engine can optimize I/O without COBOL program intervention.
15.3.2 Multi-Key Sorting
Real-world sorts almost always involve multiple keys. GlobalBank's nightly batch requires transactions sorted first by account number (to match against the master file), then by transaction date (for chronological processing within each account), and finally by amount descending (to process the largest transactions first for overdraft detection):
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
ON ASCENDING KEY SR-TRANS-DATE
ON DESCENDING KEY SR-AMOUNT
USING TRANS-IN
GIVING TRANS-OUT
You can also combine multiple keys in a single ON clause:
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
SR-TRANS-DATE
ON DESCENDING KEY SR-AMOUNT
USING TRANS-IN
GIVING TRANS-OUT
When multiple keys share the same sort direction, listing them together is more readable. The sort processes keys left to right in the order specified — the first key is the major sort key, and subsequent keys are minor sort keys used to break ties.
💡 How Multi-Key Sorting Works: Think of it as "sort by account number first; within the same account number, sort by date; within the same account and date, sort by amount descending." Each subsequent key only matters when all previous keys are equal.
15.3.3 Multiple Input Files
The USING phrase can name more than one input file. The sort reads and combines all records from all named files, then sorts them together:
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
USING TRANS-FILE-1
TRANS-FILE-2
TRANS-FILE-3
GIVING SORTED-TRANS
This is useful when transactions arrive from multiple sources (ATM transactions, online banking, branch transactions) and must be combined into a single sorted file.
15.3.4 Multiple Output Files
Similarly, GIVING can name multiple files. Each output file receives a complete copy of the sorted data:
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
USING TRANS-IN
GIVING SORTED-TRANS
SORTED-TRANS-BACKUP
⚠️ Note: Multiple GIVING files each get the entire sorted output — this is not a split operation. If you need to split sorted output into separate files based on criteria, use an OUTPUT PROCEDURE.
15.4 INPUT PROCEDURE: Filtering and Transforming Before Sort
The USING phrase reads every record from the input file and passes it directly to the sort. But what if you need to:
- Filter records (sort only deposits, ignore withdrawals)?
- Transform data (convert date formats before sorting)?
- Validate records (reject malformed records)?
- Read from multiple sources with different record layouts?
This is where the INPUT PROCEDURE comes in. An INPUT PROCEDURE is a section or range of paragraphs in your PROCEDURE DIVISION that the SORT verb invokes to supply records. Instead of reading from a file automatically, the sort calls your code, and your code feeds records to the sort one at a time using the RELEASE statement.
15.4.1 INPUT PROCEDURE Syntax
SORT sort-file-name
ON ASCENDING KEY key-field
INPUT PROCEDURE IS section-name-1
[THRU section-name-2]
GIVING output-file-name
Or equivalently:
INPUT PROCEDURE IS paragraph-name-1
[THRU paragraph-name-2]
15.4.2 The RELEASE Statement
Inside an INPUT PROCEDURE, you use RELEASE to pass a record to the sort:
RELEASE sort-record-name FROM data-name
Or simply:
RELEASE sort-record-name
The first form moves data from data-name to the sort record and then releases it. The second form assumes you have already moved data into the sort record area.
15.4.3 Example: Filtering During Sort
Here is a program that sorts only deposit transactions, skipping withdrawals and transfers:
IDENTIFICATION DIVISION.
PROGRAM-ID. SORT-FILTER.
*================================================================
* Program: SORT-FILTER
* Purpose: Sort only deposit transactions by account + date
* GlobalBank: Filter deposits for interest calculation run
*================================================================
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SORT-FILE ASSIGN TO SORTWK01.
SELECT TRANS-IN ASSIGN TO INFILE.
SELECT TRANS-OUT ASSIGN TO OUTFILE.
DATA DIVISION.
FILE SECTION.
SD SORT-FILE.
01 SORT-REC.
05 SR-ACCT-NUM PIC X(10).
05 SR-TRANS-DATE PIC 9(08).
05 SR-TRANS-TYPE PIC X(01).
88 SR-DEPOSIT VALUE 'D'.
88 SR-WITHDRAWAL VALUE 'W'.
88 SR-TRANSFER VALUE 'T'.
05 SR-AMOUNT PIC S9(09)V99 COMP-3.
05 SR-DESC PIC X(30).
05 FILLER PIC X(34).
FD TRANS-IN
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 TRANS-IN-REC.
05 TI-ACCT-NUM PIC X(10).
05 TI-TRANS-DATE PIC 9(08).
05 TI-TRANS-TYPE PIC X(01).
05 TI-AMOUNT PIC S9(09)V99 COMP-3.
05 TI-DESC PIC X(30).
05 FILLER PIC X(34).
FD TRANS-OUT
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 TRANS-OUT-REC PIC X(90).
WORKING-STORAGE SECTION.
01 WS-EOF-FLAG PIC X(01) VALUE 'N'.
88 END-OF-FILE VALUE 'Y'.
01 WS-RECORDS-READ PIC 9(09) VALUE ZERO.
01 WS-RECORDS-SORTED PIC 9(09) VALUE ZERO.
PROCEDURE DIVISION.
0000-MAIN.
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
ON ASCENDING KEY SR-TRANS-DATE
INPUT PROCEDURE IS 1000-SELECT-DEPOSITS
GIVING TRANS-OUT
DISPLAY 'RECORDS READ: ' WS-RECORDS-READ
DISPLAY 'RECORDS SORTED: ' WS-RECORDS-SORTED
STOP RUN.
1000-SELECT-DEPOSITS.
OPEN INPUT TRANS-IN
PERFORM 1100-READ-AND-FILTER
UNTIL END-OF-FILE
CLOSE TRANS-IN.
1100-READ-AND-FILTER.
READ TRANS-IN
AT END
SET END-OF-FILE TO TRUE
NOT AT END
ADD 1 TO WS-RECORDS-READ
IF TI-TRANS-TYPE = 'D'
RELEASE SORT-REC FROM TRANS-IN-REC
ADD 1 TO WS-RECORDS-SORTED
END-IF
END-READ.
📊 Counting Records: Notice how we maintain counters for records read and records released. This is a best practice for auditability — production batch jobs almost always report record counts for reconciliation.
15.4.4 Example: Transforming During Sort
Sometimes you need to modify records before sorting. At GlobalBank, branch codes were recently restructured from a 3-character to a 5-character format. Legacy transaction files still contain the old codes, but the sort must use the new format:
1000-TRANSFORM-AND-SORT.
OPEN INPUT TRANS-IN
PERFORM 1100-PROCESS-RECORD
UNTIL END-OF-FILE
CLOSE TRANS-IN.
1100-PROCESS-RECORD.
READ TRANS-IN
AT END
SET END-OF-FILE TO TRUE
NOT AT END
ADD 1 TO WS-RECORDS-READ
MOVE TRANS-IN-REC TO SORT-REC
PERFORM 1200-CONVERT-BRANCH-CODE
RELEASE SORT-REC
ADD 1 TO WS-RECORDS-SORTED
END-READ.
1200-CONVERT-BRANCH-CODE.
EVALUATE SR-OLD-BRANCH
WHEN 'NYC'
MOVE 'NYC01' TO SR-NEW-BRANCH
WHEN 'CHI'
MOVE 'CHI01' TO SR-NEW-BRANCH
WHEN 'LAX'
MOVE 'LAX01' TO SR-NEW-BRANCH
WHEN OTHER
MOVE 'UNK00' TO SR-NEW-BRANCH
ADD 1 TO WS-UNKNOWN-BRANCHES
END-EVALUATE.
⚠️ Important Rule: Inside an INPUT PROCEDURE, you must not reference the input file named in a USING clause (because there is no USING clause — you replaced it). You manage the input file yourself: you OPEN it, READ from it, and CLOSE it. The only "special" operation is the RELEASE statement that feeds records to the sort.
15.5 OUTPUT PROCEDURE: Processing After Sort
Just as an INPUT PROCEDURE replaces USING, an OUTPUT PROCEDURE replaces GIVING. An OUTPUT PROCEDURE is a section or paragraph range that the SORT invokes after all records have been sorted. Your code retrieves sorted records one at a time using the RETURN statement.
15.5.1 OUTPUT PROCEDURE Syntax
SORT sort-file-name
ON ASCENDING KEY key-field
USING input-file-name
OUTPUT PROCEDURE IS section-name-1
[THRU section-name-2]
15.5.2 The RETURN Statement
The RETURN statement retrieves the next record from the sort in sorted order:
RETURN sort-file-name [INTO data-name]
AT END imperative-statement
[NOT AT END imperative-statement]
END-RETURN
The AT END condition is raised when all sorted records have been retrieved. This parallels the READ statement's AT END for regular files.
15.5.3 Example: Control Break Report from Sorted Data
This is one of the most common patterns in batch COBOL: sort a file, then process the sorted output to produce a control break report. At GlobalBank, Derek needs to produce a daily summary showing total deposits and withdrawals per account:
PROCEDURE DIVISION.
0000-MAIN.
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
ON ASCENDING KEY SR-TRANS-DATE
USING TRANS-IN
OUTPUT PROCEDURE IS 2000-PRODUCE-REPORT
DISPLAY 'REPORT COMPLETE. ACCOUNTS: '
WS-ACCOUNT-COUNT
STOP RUN.
2000-PRODUCE-REPORT.
OPEN OUTPUT REPORT-FILE
PERFORM 2050-WRITE-REPORT-HEADERS
PERFORM 2100-GET-FIRST-RECORD
PERFORM 2200-PROCESS-ACCOUNT
UNTIL END-OF-SORT
PERFORM 2800-WRITE-GRAND-TOTALS
CLOSE REPORT-FILE.
2100-GET-FIRST-RECORD.
RETURN SORT-FILE INTO WS-TRANS-REC
AT END
SET END-OF-SORT TO TRUE
NOT AT END
MOVE WT-ACCT-NUM TO WS-PREV-ACCT
END-RETURN.
2200-PROCESS-ACCOUNT.
MOVE ZEROS TO WS-ACCT-DEPOSITS
WS-ACCT-WITHDRAWALS
WS-ACCT-TRANS-COUNT
PERFORM 2300-ACCUMULATE-ACCOUNT
UNTIL END-OF-SORT
OR WT-ACCT-NUM NOT = WS-PREV-ACCT
PERFORM 2400-WRITE-ACCOUNT-SUMMARY
ADD 1 TO WS-ACCOUNT-COUNT
IF NOT END-OF-SORT
MOVE WT-ACCT-NUM TO WS-PREV-ACCT
END-IF.
2300-ACCUMULATE-ACCOUNT.
ADD 1 TO WS-ACCT-TRANS-COUNT
EVALUATE WT-TRANS-TYPE
WHEN 'D'
ADD WT-AMOUNT TO WS-ACCT-DEPOSITS
WHEN 'W'
ADD WT-AMOUNT TO WS-ACCT-WITHDRAWALS
END-EVALUATE
RETURN SORT-FILE INTO WS-TRANS-REC
AT END
SET END-OF-SORT TO TRUE
END-RETURN.
2400-WRITE-ACCOUNT-SUMMARY.
MOVE WS-PREV-ACCT TO RPT-ACCT-NUM
MOVE WS-ACCT-DEPOSITS TO RPT-DEPOSITS
MOVE WS-ACCT-WITHDRAWALS TO RPT-WITHDRAWALS
COMPUTE RPT-NET = WS-ACCT-DEPOSITS
- WS-ACCT-WITHDRAWALS
MOVE WS-ACCT-TRANS-COUNT TO RPT-TRANS-CNT
WRITE REPORT-REC FROM WS-DETAIL-LINE
AFTER ADVANCING 1 LINE.
🔗 Cross-Reference: This control-break pattern within an OUTPUT PROCEDURE connects directly to the Report Writer approach we explore in Chapter 16. Many of the same reports can be written either way — the choice depends on complexity and team preference.
15.6 Combining INPUT and OUTPUT PROCEDUREs
You can use both an INPUT PROCEDURE and an OUTPUT PROCEDURE in the same SORT statement:
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
INPUT PROCEDURE IS 1000-FILTER-INPUT
OUTPUT PROCEDURE IS 2000-PRODUCE-REPORT
This gives you maximum control: you filter and transform records on the way in, and you process sorted records on the way out. The sort utility handles everything in between.
15.6.1 Complete Example: GlobalBank Transaction Sort
Let us build a complete program that Maria Chen uses at GlobalBank. This program:
- Reads daily transactions from multiple sources
- Validates each transaction (INPUT PROCEDURE)
- Sorts by account number, then date, then amount descending
- Produces a sorted output file AND a summary report (OUTPUT PROCEDURE)
IDENTIFICATION DIVISION.
PROGRAM-ID. GBSORT01.
*================================================================
* Program: GBSORT01
* Purpose: GlobalBank daily transaction sort with validation
* and summary reporting
* Author: Maria Chen / Derek Washington
* Date: 2024-01-15
*================================================================
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SORT-WORK ASSIGN TO SORTWK01.
SELECT TXN-INPUT ASSIGN TO TXNIN.
SELECT TXN-SORTED ASSIGN TO TXNOUT.
SELECT ERROR-FILE ASSIGN TO ERRFILE.
SELECT SUMMARY-RPT ASSIGN TO SUMRPT.
DATA DIVISION.
FILE SECTION.
SD SORT-WORK.
01 SORT-REC.
05 SR-ACCT-NUM PIC X(10).
05 SR-TXN-DATE PIC 9(08).
05 SR-TXN-TIME PIC 9(06).
05 SR-TXN-TYPE PIC X(01).
88 SR-VALID-TYPE VALUE 'D' 'W' 'T' 'F' 'I'.
05 SR-AMOUNT PIC S9(09)V99 COMP-3.
05 SR-BRANCH PIC X(05).
05 SR-TELLER PIC X(06).
05 SR-DESC PIC X(30).
05 FILLER PIC X(22).
FD TXN-INPUT
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 TXN-IN-REC PIC X(100).
FD TXN-SORTED
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 TXN-SORTED-REC PIC X(100).
FD ERROR-FILE
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 ERROR-REC PIC X(150).
FD SUMMARY-RPT
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 SUMMARY-REC PIC X(132).
WORKING-STORAGE SECTION.
01 WS-FLAGS.
05 WS-EOF-INPUT PIC X(01) VALUE 'N'.
88 EOF-INPUT VALUE 'Y'.
05 WS-EOF-SORT PIC X(01) VALUE 'N'.
88 EOF-SORT VALUE 'Y'.
01 WS-COUNTERS.
05 WS-READ-CNT PIC 9(09) VALUE ZERO.
05 WS-VALID-CNT PIC 9(09) VALUE ZERO.
05 WS-ERROR-CNT PIC 9(09) VALUE ZERO.
05 WS-WRITTEN-CNT PIC 9(09) VALUE ZERO.
01 WS-CURRENT-REC.
05 WC-ACCT-NUM PIC X(10).
05 WC-TXN-DATE PIC 9(08).
05 WC-TXN-TIME PIC 9(06).
05 WC-TXN-TYPE PIC X(01).
05 WC-AMOUNT PIC S9(09)V99 COMP-3.
05 WC-BRANCH PIC X(05).
05 WC-TELLER PIC X(06).
05 WC-DESC PIC X(30).
05 FILLER PIC X(22).
01 WS-ERROR-DETAIL.
05 WE-RECORD PIC X(100).
05 WE-REASON PIC X(50).
01 WS-PREV-ACCT PIC X(10).
01 WS-ACCT-TOTAL PIC S9(11)V99 VALUE ZERO.
01 WS-GRAND-TOTAL PIC S9(13)V99 VALUE ZERO.
01 WS-ACCT-COUNT PIC 9(07) VALUE ZERO.
PROCEDURE DIVISION.
0000-MAIN.
SORT SORT-WORK
ON ASCENDING KEY SR-ACCT-NUM
ON ASCENDING KEY SR-TXN-DATE
ON ASCENDING KEY SR-TXN-TIME
ON DESCENDING KEY SR-AMOUNT
WITH DUPLICATES IN ORDER
INPUT PROCEDURE IS 1000-VALIDATE-INPUT
OUTPUT PROCEDURE IS 2000-WRITE-OUTPUT
DISPLAY '========================================='
DISPLAY 'GBSORT01 PROCESSING COMPLETE'
DISPLAY ' RECORDS READ: ' WS-READ-CNT
DISPLAY ' RECORDS SORTED: ' WS-VALID-CNT
DISPLAY ' RECORDS REJECTED:' WS-ERROR-CNT
DISPLAY ' RECORDS WRITTEN: ' WS-WRITTEN-CNT
DISPLAY ' ACCOUNTS FOUND: ' WS-ACCT-COUNT
DISPLAY '========================================='
STOP RUN.
1000-VALIDATE-INPUT.
OPEN INPUT TXN-INPUT
OPEN OUTPUT ERROR-FILE
PERFORM 1100-READ-VALIDATE
UNTIL EOF-INPUT
CLOSE TXN-INPUT
CLOSE ERROR-FILE.
1100-READ-VALIDATE.
READ TXN-INPUT INTO WS-CURRENT-REC
AT END
SET EOF-INPUT TO TRUE
NOT AT END
ADD 1 TO WS-READ-CNT
PERFORM 1200-VALIDATE-RECORD
END-READ.
1200-VALIDATE-RECORD.
* Check account number is not spaces
IF WC-ACCT-NUM = SPACES
MOVE 'BLANK ACCOUNT NUMBER' TO WE-REASON
PERFORM 1300-WRITE-ERROR
RETURN
END-IF
* Check transaction date is numeric and valid range
IF WC-TXN-DATE NOT NUMERIC
MOVE 'NON-NUMERIC DATE' TO WE-REASON
PERFORM 1300-WRITE-ERROR
RETURN
END-IF
IF WC-TXN-DATE < 20200101
OR WC-TXN-DATE > 20251231
MOVE 'DATE OUT OF RANGE' TO WE-REASON
PERFORM 1300-WRITE-ERROR
RETURN
END-IF
* Check transaction type is valid
IF WC-TXN-TYPE NOT = 'D' AND 'W' AND 'T'
AND 'F' AND 'I'
MOVE 'INVALID TRANSACTION TYPE' TO WE-REASON
PERFORM 1300-WRITE-ERROR
RETURN
END-IF
* Check amount is reasonable
IF WC-AMOUNT = ZERO
MOVE 'ZERO AMOUNT' TO WE-REASON
PERFORM 1300-WRITE-ERROR
RETURN
END-IF
* Record passed all validations — release to sort
RELEASE SORT-REC FROM WS-CURRENT-REC
ADD 1 TO WS-VALID-CNT.
1300-WRITE-ERROR.
MOVE WS-CURRENT-REC TO WE-RECORD
WRITE ERROR-REC FROM WS-ERROR-DETAIL
ADD 1 TO WS-ERROR-CNT.
2000-WRITE-OUTPUT.
OPEN OUTPUT TXN-SORTED
OPEN OUTPUT SUMMARY-RPT
PERFORM 2100-GET-FIRST-SORTED
PERFORM 2200-PROCESS-SORTED
UNTIL EOF-SORT
PERFORM 2500-WRITE-GRAND-TOTALS
CLOSE TXN-SORTED
CLOSE SUMMARY-RPT.
2100-GET-FIRST-SORTED.
RETURN SORT-WORK INTO WS-CURRENT-REC
AT END
SET EOF-SORT TO TRUE
NOT AT END
MOVE WC-ACCT-NUM TO WS-PREV-ACCT
MOVE ZERO TO WS-ACCT-TOTAL
END-RETURN.
2200-PROCESS-SORTED.
* Write the sorted record
WRITE TXN-SORTED-REC FROM WS-CURRENT-REC
ADD 1 TO WS-WRITTEN-CNT
ADD WC-AMOUNT TO WS-ACCT-TOTAL
* Get next record
RETURN SORT-WORK INTO WS-CURRENT-REC
AT END
SET EOF-SORT TO TRUE
PERFORM 2300-ACCOUNT-BREAK
NOT AT END
IF WC-ACCT-NUM NOT = WS-PREV-ACCT
PERFORM 2300-ACCOUNT-BREAK
MOVE WC-ACCT-NUM TO WS-PREV-ACCT
MOVE ZERO TO WS-ACCT-TOTAL
END-IF
END-RETURN.
2300-ACCOUNT-BREAK.
ADD 1 TO WS-ACCT-COUNT
ADD WS-ACCT-TOTAL TO WS-GRAND-TOTAL
PERFORM 2400-WRITE-ACCT-SUMMARY.
2400-WRITE-ACCT-SUMMARY.
INITIALIZE SUMMARY-REC
STRING 'ACCOUNT: ' WS-PREV-ACCT
' NET ACTIVITY: '
DELIMITED BY SIZE
INTO SUMMARY-REC
WRITE SUMMARY-REC.
2500-WRITE-GRAND-TOTALS.
INITIALIZE SUMMARY-REC
MOVE '========================================='
TO SUMMARY-REC
WRITE SUMMARY-REC
INITIALIZE SUMMARY-REC
STRING 'GRAND TOTAL NET ACTIVITY: '
DELIMITED BY SIZE
INTO SUMMARY-REC
WRITE SUMMARY-REC.
🧪 Try It Yourself: In your Student Mainframe Lab, create a transaction file with some deliberately invalid records (blank account numbers, non-numeric dates, zero amounts). Run GBSORT01 and verify that the error file catches the bad records while the sorted output contains only valid records. Check that the record counts in the DISPLAY output reconcile: READ-CNT should equal VALID-CNT plus ERROR-CNT.
15.7 The MERGE Verb
While SORT arranges records from one or more unsorted files, MERGE combines records from two or more files that are already sorted on the same key. The MERGE verb interleaves records from its input files to produce a single, properly ordered output.
15.7.1 MERGE Syntax
MERGE merge-file-name
ON {ASCENDING | DESCENDING} KEY data-name-1 [data-name-2 ...]
[COLLATING SEQUENCE IS alphabet-name]
USING input-file-1 input-file-2 [input-file-3 ...]
{GIVING output-file-name |
OUTPUT PROCEDURE IS section-name}
Key differences from SORT:
- MERGE requires at least two input files in the USING clause (SORT requires at least one)
- MERGE does not support INPUT PROCEDURE — the input files must already be in the correct sort order
- MERGE does support OUTPUT PROCEDURE for post-merge processing
- The merge file uses an SD entry, just like a sort file
⚠️ Critical Prerequisite: Each input file to MERGE must already be sorted on the same key(s) specified in the MERGE statement. If a file is not properly sorted, the results are undefined — the merge utility may produce incorrect output without any error message. Always verify your input file sort order!
15.7.2 MERGE Example: Combining Regional Transaction Files
At GlobalBank, each region produces its own sorted transaction file overnight. These must be merged into a single national file for consolidated processing:
IDENTIFICATION DIVISION.
PROGRAM-ID. GBMERGE01.
*================================================================
* Program: GBMERGE01
* Purpose: Merge regional transaction files into national file
* Note: All input files MUST be pre-sorted on account number
*================================================================
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT MERGE-FILE ASSIGN TO SORTWK01.
SELECT EAST-TRANS ASSIGN TO EASTIN.
SELECT CENTRAL-TRANS ASSIGN TO CENTRIN.
SELECT WEST-TRANS ASSIGN TO WESTIN.
SELECT NATIONAL-FILE ASSIGN TO NATOUT.
DATA DIVISION.
FILE SECTION.
SD MERGE-FILE.
01 MERGE-REC.
05 MR-ACCT-NUM PIC X(10).
05 MR-TXN-DATE PIC 9(08).
05 MR-REGION PIC X(02).
05 FILLER PIC X(80).
FD EAST-TRANS
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 EAST-REC PIC X(100).
FD CENTRAL-TRANS
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 CENTRAL-REC PIC X(100).
FD WEST-TRANS
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 WEST-REC PIC X(100).
FD NATIONAL-FILE
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 NATIONAL-REC PIC X(100).
PROCEDURE DIVISION.
0000-MAIN.
MERGE MERGE-FILE
ON ASCENDING KEY MR-ACCT-NUM
ON ASCENDING KEY MR-TXN-DATE
USING EAST-TRANS
CENTRAL-TRANS
WEST-TRANS
GIVING NATIONAL-FILE
STOP RUN.
15.7.3 MERGE with OUTPUT PROCEDURE
You can use an OUTPUT PROCEDURE with MERGE to process records as they come out of the merge. This is useful for detecting duplicates across the merged files:
MERGE MERGE-FILE
ON ASCENDING KEY MR-ACCT-NUM
ON ASCENDING KEY MR-TXN-DATE
USING EAST-TRANS
CENTRAL-TRANS
WEST-TRANS
OUTPUT PROCEDURE IS 3000-DEDUP-AND-WRITE
3000-DEDUP-AND-WRITE.
OPEN OUTPUT NATIONAL-FILE
MOVE LOW-VALUES TO WS-PREV-KEY
PERFORM 3100-GET-MERGED
UNTIL EOF-MERGE
CLOSE NATIONAL-FILE.
3100-GET-MERGED.
RETURN MERGE-FILE INTO WS-MERGE-REC
AT END
SET EOF-MERGE TO TRUE
NOT AT END
IF WM-FULL-KEY = WS-PREV-KEY
ADD 1 TO WS-DUP-COUNT
ELSE
WRITE NATIONAL-REC FROM WS-MERGE-REC
ADD 1 TO WS-WRITE-COUNT
MOVE WM-FULL-KEY TO WS-PREV-KEY
END-IF
END-RETURN.
💡 SORT vs. MERGE Performance: MERGE is significantly faster than SORT when input files are already sorted, because it avoids the internal sort phase entirely. A merge operation is O(n) — it simply interleaves already-ordered sequences. A sort is O(n log n). For very large files, this difference matters enormously.
15.8 Sort Error Handling — Defensive Programming
The theme of this chapter is Defensive Programming, and nowhere is it more important than in sort operations. A failed sort can halt an entire batch cycle. Let us examine how to detect and handle sort errors.
15.8.1 The SORT Special Register
After a SORT or MERGE statement executes, the special register SORT-RETURN contains the return code:
| Value | Meaning |
|---|---|
| 0 | Sort completed successfully |
| 16 | Sort terminated abnormally |
You can check SORT-RETURN immediately after the SORT statement:
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
USING TRANS-IN
GIVING TRANS-OUT
IF SORT-RETURN NOT = ZERO
DISPLAY 'SORT FAILED WITH RC = ' SORT-RETURN
MOVE 16 TO RETURN-CODE
STOP RUN
END-IF
15.8.2 Setting SORT-RETURN to Cancel a Sort
You can set SORT-RETURN to 16 inside an INPUT or OUTPUT PROCEDURE to force the sort to terminate:
1200-VALIDATE-RECORD.
IF WC-ERROR-COUNT > WS-MAX-ERRORS
DISPLAY 'TOO MANY ERRORS - ABORTING SORT'
MOVE 16 TO SORT-RETURN
END-IF.
When you set SORT-RETURN to 16, the sort utility terminates as soon as control returns from your INPUT or OUTPUT PROCEDURE. This is the graceful way to abort a sort when data quality is too poor to continue.
⚠️ Defense Pattern — The Error Threshold: James Okafor at MedClaim follows a strict rule: "If more than 1% of records fail validation, something is wrong with the feed — don't sort, don't process, escalate immediately." This error threshold pattern is a defensive programming best practice:
1200-CHECK-ERROR-THRESHOLD.
IF WS-READ-CNT > 100
COMPUTE WS-ERROR-PCT =
(WS-ERROR-CNT / WS-READ-CNT) * 100
IF WS-ERROR-PCT > 1
DISPLAY 'ERROR RATE EXCEEDS 1% - ABORTING'
DISPLAY 'ERRORS: ' WS-ERROR-CNT
' OF ' WS-READ-CNT ' RECORDS'
MOVE 16 TO SORT-RETURN
END-IF
END-IF.
15.8.3 Sort Return Code in JCL
The SORT-RETURN value flows through to the JCL COND parameter, allowing subsequent job steps to check whether the sort succeeded:
//STEP020 EXEC PGM=BALPROG
// COND=(4,LT,STEP010)
This step runs only if STEP010 (the sort step) returned a code less than 4 — effectively, only if the sort succeeded.
15.8.4 Common Sort Failures and Their Causes
| Failure | Typical Cause | Prevention |
|---|---|---|
| S0C7 ABEND | Non-numeric data in numeric sort key | Validate data in INPUT PROCEDURE |
| S001 ABEND | I/O error on input/output file | Check file status, verify DD statements |
| S37 ABEND | Sort work space full | Allocate sufficient SORTWK space |
| SB37 ABEND | Output file space exhausted | Estimate output size, use SMS-managed space |
| Incorrect results | Input to MERGE not pre-sorted | Verify sort order before MERGE |
| Incorrect results | Wrong key field offset | Verify SD record layout matches actual data |
🔴 War Story: Derek Washington spent an entire afternoon debugging a sort that produced subtly wrong results. The sorted output looked sorted, but downstream account balancing was off. The culprit? The SD record layout had a FILLER field that was one byte too short, causing all subsequent fields to be misaligned. The sort was ordering by what it thought was the account number — but was actually the last digit of the account number followed by the first seven digits of the date. Lesson: always verify your SD layout against the actual file record layout, byte by byte.
15.9 External Sort Utilities: DFSORT and SyncSort
On IBM mainframes, the COBOL SORT verb invokes an external sort utility — most commonly DFSORT (IBM's licensed sort product) or SyncSort (now Precisely SyncSort). Understanding these utilities helps you optimize sort performance and leverage features beyond what COBOL's SORT verb directly exposes.
15.9.1 How COBOL Invokes the Sort Utility
When your COBOL program executes a SORT statement, the following happens:
- The COBOL runtime calls the sort utility's API
- If using USING/GIVING, the sort utility handles all I/O directly
- If using INPUT/OUTPUT PROCEDURE, the sort utility calls back to your COBOL code via the RELEASE/RETURN mechanism
- The sort utility manages sort work files, memory allocation, and the sort algorithm
You generally do not need to configure the sort utility — it works through sensible defaults. However, you can influence its behavior through:
- JCL PARM statements on the sort step
- SORTCNTL DD statements with sort control cards
- DFSPARM DD for DFSORT-specific options
15.9.2 DFSORT Control Statements
Sometimes you want to use DFSORT features that COBOL's SORT verb cannot express. You can pass control statements through the DFSPARM DD:
//DFSPARM DD *
OPTION DYNALLOC=(SYSDA,5)
OPTION FILSZ=E1000000
/*
- DYNALLOC: Dynamically allocates sort work datasets (saves you from coding SORTWK DD statements)
- FILSZ: Tells the sort how many records to expect, enabling better memory allocation
15.9.3 When to Use JCL Sort Instead of COBOL SORT
For simple sort-only operations with no filtering or transformation, a standalone DFSORT step in JCL is often preferable:
//SORTJOB EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=PROD.TRANS.DAILY,DISP=SHR
//SORTOUT DD DSN=PROD.TRANS.SORTED,DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(50,10)),UNIT=SYSDA
//SYSIN DD *
SORT FIELDS=(1,10,CH,A,11,8,CH,A)
OPTION EQUALS
/*
Advantages of JCL sort: - No COBOL program to compile and maintain - Directly leverages all sort utility features - Often faster for simple sorts (no COBOL overhead) - Easier to modify (change JCL, not source code)
Advantages of COBOL SORT: - Complex filtering and transformation via INPUT/OUTPUT PROCEDUREs - Sort logic documented alongside business logic - Conditional sorting based on program state - Integration with program variables and control flow
📊 Decision Guide: Maria Chen's rule at GlobalBank: "If you're just reordering records, use JCL SORT. If you need to think about the records while sorting them, use COBOL SORT."
15.9.4 Performance Tuning the Sort
For large-volume sorts (millions of records), performance matters. Key tuning parameters:
-
Memory allocation: More memory means fewer merge passes. DFSORT's MAINSIZE option controls this:
OPTION MAINSIZE=MAX -
Sort work datasets: More datasets allow parallel I/O. Three to six sort work datasets is typical for large sorts.
-
Key position: Keep sort keys at the beginning of the record when possible — some sort utilities can optimize key comparison when keys are contiguous and at the start of the record.
-
Record length: Shorter records sort faster. If you are sorting very long records on a short key, consider extracting keys, sorting the key file, and then resequencing the original file (a tag sort).
-
FASTSRT compiler option: The Enterprise COBOL FASTSRT compiler option allows the sort utility to handle I/O directly when USING/GIVING is specified, bypassing COBOL's I/O routines. This can significantly improve performance:
jcl //COBOL.SYSIN DD * CBL FASTSRT
✅ Best Practice: Always specify FASTSRT unless you have specific reasons not to. The only case where FASTSRT is incompatible is when the FD for the sort input/output file has special characteristics (APPLY WRITE-ONLY, certain LINAGE specifications, etc.).
15.10 Advanced Sort Patterns
15.10.1 Sorting with Variable-Length Records
COBOL's SORT handles variable-length records, but you must declare the record properly:
SD SORT-FILE
RECORD IS VARYING IN SIZE
FROM 50 TO 500 CHARACTERS
DEPENDING ON WS-SORT-REC-LEN.
01 SORT-REC.
05 SR-REC-TYPE PIC X(02).
05 SR-KEY PIC X(20).
05 SR-DATA PIC X(478).
15.10.2 Sorting a Table (Array) in Memory
The SORT verb works only with files, not with tables in memory. To sort an in-memory table, you have several options:
- Write the table to a temporary file, sort it, read it back — cumbersome but uses the efficient external sort
- Write your own sort algorithm — bubble sort for small tables, quicksort for larger ones
- Use SORT with an INPUT/OUTPUT PROCEDURE that RELEASEs table entries and RETURNs them back into the table
The third approach is elegant:
PROCEDURE DIVISION.
0000-MAIN.
PERFORM 0100-LOAD-TABLE
SORT SORT-FILE
ON ASCENDING KEY SR-EMPLOYEE-ID
INPUT PROCEDURE IS 1000-RELEASE-TABLE
OUTPUT PROCEDURE IS 2000-RETURN-TABLE
PERFORM 0200-PROCESS-SORTED-TABLE
STOP RUN.
1000-RELEASE-TABLE.
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > WS-TABLE-SIZE
RELEASE SORT-REC FROM TABLE-ENTRY(WS-IDX)
END-PERFORM.
2000-RETURN-TABLE.
MOVE ZERO TO WS-IDX
PERFORM 2100-GET-SORTED-ENTRY
UNTIL EOF-SORT.
2100-GET-SORTED-ENTRY.
ADD 1 TO WS-IDX
RETURN SORT-FILE INTO TABLE-ENTRY(WS-IDX)
AT END
SET EOF-SORT TO TRUE
END-RETURN.
🧪 Try It Yourself: Create a program that loads 20 employee records into a table, sorts the table by last name using the INPUT/OUTPUT PROCEDURE technique, and then displays the sorted table. Compare this approach with writing a simple bubble sort paragraph. Which is more readable? Which would you prefer in production code?
15.10.3 The WITH DUPLICATES IN ORDER Clause
By default, when two records have identical sort keys, their relative order in the output is implementation-dependent. The WITH DUPLICATES IN ORDER clause guarantees stability — records with equal keys appear in the same order as they appeared in the input.
This matters for audit trails and regulatory compliance:
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
WITH DUPLICATES IN ORDER
USING TRANS-IN
GIVING TRANS-OUT
When multiple transactions for the same account arrive in chronological order but are sorted only by account (not by time), WITHOUT the DUPLICATES IN ORDER clause, transactions within the same account might appear in random order. WITH the clause, they remain in their original chronological sequence.
📊 Performance Note: WITH DUPLICATES IN ORDER may slightly reduce sort performance because the sort utility must track original record positions. For very large files, test whether the performance impact is acceptable.
15.11 MedClaim Case Study: Sorting Claims for Batch Adjudication
Let us examine how MedClaim uses SORT in their claims processing pipeline. James Okafor's team needs to sort incoming claims for batch adjudication. The sort must:
- Filter out duplicate claim submissions (same claim ID submitted twice)
- Validate provider numbers against a valid range
- Sort by provider number, then claim date, for efficient provider-batch processing
- Track statistics for the nightly operations dashboard
IDENTIFICATION DIVISION.
PROGRAM-ID. MCSORT01.
*================================================================
* Program: MCSORT01
* Purpose: MedClaim - Sort claims for batch adjudication
* Author: James Okafor / Sarah Kim
* Notes: Claims sorted by provider then date for efficient
* batch adjudication processing
*================================================================
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SORT-WORK ASSIGN TO SORTWK01.
SELECT CLAIMS-IN ASSIGN TO CLMIN.
SELECT CLAIMS-SORTED ASSIGN TO CLMOUT.
SELECT DUPLICATES-FL ASSIGN TO DUPFILE.
DATA DIVISION.
FILE SECTION.
SD SORT-WORK.
01 SORT-CLAIM.
05 SC-PROVIDER-NUM PIC X(10).
05 SC-CLAIM-DATE PIC 9(08).
05 SC-CLAIM-ID PIC X(15).
05 SC-MEMBER-ID PIC X(12).
05 SC-DIAG-CODE PIC X(07).
05 SC-PROC-CODE PIC X(05).
05 SC-CHARGE-AMT PIC S9(07)V99 COMP-3.
05 SC-FACILITY PIC X(06).
05 FILLER PIC X(30).
FD CLAIMS-IN
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 CLAIM-IN-REC PIC X(100).
FD CLAIMS-SORTED
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 CLAIM-SORTED-REC PIC X(100).
FD DUPLICATES-FL
RECORDING MODE IS F
BLOCK CONTAINS 0 RECORDS.
01 DUPLICATE-REC PIC X(100).
WORKING-STORAGE SECTION.
01 WS-FLAGS.
05 WS-EOF-IN PIC X VALUE 'N'.
88 EOF-IN VALUE 'Y'.
05 WS-EOF-SORT PIC X VALUE 'N'.
88 EOF-SORT VALUE 'Y'.
01 WS-COUNTERS.
05 WS-READ-CNT PIC 9(07) VALUE ZERO.
05 WS-RELEASED-CNT PIC 9(07) VALUE ZERO.
05 WS-DUP-CNT PIC 9(07) VALUE ZERO.
05 WS-BAD-PROV-CNT PIC 9(07) VALUE ZERO.
05 WS-WRITTEN-CNT PIC 9(07) VALUE ZERO.
01 WS-PREV-CLAIM-ID PIC X(15) VALUE LOW-VALUES.
01 WS-CLAIM-WORK.
05 WW-PROVIDER-NUM PIC X(10).
05 WW-CLAIM-DATE PIC 9(08).
05 WW-CLAIM-ID PIC X(15).
05 WW-MEMBER-ID PIC X(12).
05 WW-DIAG-CODE PIC X(07).
05 WW-PROC-CODE PIC X(05).
05 WW-CHARGE-AMT PIC S9(07)V99 COMP-3.
05 WW-FACILITY PIC X(06).
05 FILLER PIC X(30).
PROCEDURE DIVISION.
0000-MAIN.
SORT SORT-WORK
ON ASCENDING KEY SC-PROVIDER-NUM
ON ASCENDING KEY SC-CLAIM-DATE
WITH DUPLICATES IN ORDER
INPUT PROCEDURE IS 1000-VALIDATE-CLAIMS
OUTPUT PROCEDURE IS 2000-DEDUP-OUTPUT
IF SORT-RETURN NOT = ZERO
DISPLAY 'MCSORT01: SORT FAILED RC='
SORT-RETURN
MOVE 16 TO RETURN-CODE
ELSE
DISPLAY 'MCSORT01: COMPLETE'
DISPLAY ' READ: ' WS-READ-CNT
DISPLAY ' RELEASED: ' WS-RELEASED-CNT
DISPLAY ' BAD PROVDR: ' WS-BAD-PROV-CNT
DISPLAY ' DUPLICATES: ' WS-DUP-CNT
DISPLAY ' WRITTEN: ' WS-WRITTEN-CNT
END-IF
STOP RUN.
1000-VALIDATE-CLAIMS.
OPEN INPUT CLAIMS-IN
PERFORM 1100-READ-AND-CHECK
UNTIL EOF-IN
CLOSE CLAIMS-IN.
1100-READ-AND-CHECK.
READ CLAIMS-IN INTO WS-CLAIM-WORK
AT END
SET EOF-IN TO TRUE
NOT AT END
ADD 1 TO WS-READ-CNT
PERFORM 1200-VALIDATE-PROVIDER
END-READ.
1200-VALIDATE-PROVIDER.
* Provider numbers must start with 'PRV' and be
* followed by 7 numeric digits
IF WW-PROVIDER-NUM(1:3) NOT = 'PRV'
ADD 1 TO WS-BAD-PROV-CNT
ELSE
IF WW-PROVIDER-NUM(4:7) NOT NUMERIC
ADD 1 TO WS-BAD-PROV-CNT
ELSE
RELEASE SORT-CLAIM FROM WS-CLAIM-WORK
ADD 1 TO WS-RELEASED-CNT
END-IF
END-IF.
2000-DEDUP-OUTPUT.
OPEN OUTPUT CLAIMS-SORTED
OPEN OUTPUT DUPLICATES-FL
MOVE LOW-VALUES TO WS-PREV-CLAIM-ID
PERFORM 2100-GET-AND-DEDUP
UNTIL EOF-SORT
CLOSE CLAIMS-SORTED
CLOSE DUPLICATES-FL.
2100-GET-AND-DEDUP.
RETURN SORT-WORK INTO WS-CLAIM-WORK
AT END
SET EOF-SORT TO TRUE
NOT AT END
IF WW-CLAIM-ID = WS-PREV-CLAIM-ID
WRITE DUPLICATE-REC
FROM WS-CLAIM-WORK
ADD 1 TO WS-DUP-CNT
ELSE
WRITE CLAIM-SORTED-REC
FROM WS-CLAIM-WORK
ADD 1 TO WS-WRITTEN-CNT
MOVE WW-CLAIM-ID
TO WS-PREV-CLAIM-ID
END-IF
END-RETURN.
🔵 Sarah Kim's Perspective: "Notice that the deduplication in the OUTPUT PROCEDURE checks claim ID, not the sort keys (provider + date). The sort brings records into provider/date order for downstream processing, but the duplicate check uses the claim's unique identifier. This is a common pattern — sort on one key, deduplicate on another."
15.12 Sort Performance Considerations
Production sort jobs at GlobalBank process millions of records nightly. Performance tuning is not academic — it directly affects whether the batch window completes before the online system must come back up at 6:00 AM.
15.12.1 Factors Affecting Sort Performance
| Factor | Impact | Optimization |
|---|---|---|
| Number of records | Linear — doubling records roughly doubles sort time | Pre-filter in INPUT PROCEDURE |
| Record length | Longer records = more I/O | Use tag sort for very long records |
| Number of keys | Minimal impact on comparison time | Group keys contiguously |
| Key position | Keys at start of record can be optimized | Place keys at beginning |
| Available memory | More memory = fewer merge passes | Use MAINSIZE=MAX |
| Sort work space | More space = better parallelism | Allocate generously |
| FASTSRT option | Bypasses COBOL I/O routines | Always use with USING/GIVING |
| Disk speed | Direct impact on I/O-bound sorts | Use fastest available DASD |
15.12.2 The Tag Sort Technique
When records are very long (say, 2000 bytes) but the sort key is short (say, 20 bytes), you can dramatically improve performance with a tag sort:
- Extract the key plus a record sequence number into a short record
- Sort the short records
- Use the sequence numbers to resequence the original file
This reduces I/O during the sort phase by a factor of 100 in this example (20 bytes vs. 2000 bytes per record).
15.12.3 FASTSRT and Its Limitations
The FASTSRT compiler option tells Enterprise COBOL to let the sort utility handle I/O directly for USING and GIVING files. This bypasses COBOL's I/O routines, avoiding overhead from:
- COBOL's internal buffering
- AT END processing
- Record area MOVEs
FASTSRT is incompatible with: - INPUT PROCEDURE or OUTPUT PROCEDURE (naturally — COBOL must handle I/O in these) - APPLY WRITE-ONLY on the FD - Certain LINAGE specifications - EXTERNAL files
When FASTSRT cannot be used, the compiler silently falls back to standard I/O without warning.
15.13 Sort and Merge Restrictions
Understanding the restrictions on SORT and MERGE prevents frustrating debugging sessions:
-
No nested SORT/MERGE: You cannot execute a SORT inside an INPUT or OUTPUT PROCEDURE of another SORT. This restriction exists because both sorts would need the same sort utility resources.
-
No GO TO out of procedures: You must not transfer control out of an INPUT or OUTPUT PROCEDURE using GO TO (some compilers allow it, but it causes undefined behavior).
-
File restrictions: Inside an INPUT PROCEDURE, you cannot reference any file named in a USING clause of the same SORT. Inside an OUTPUT PROCEDURE, you cannot reference any file named in a GIVING clause.
-
RELEASE only in INPUT PROCEDURE: The RELEASE statement is valid only within the INPUT PROCEDURE of the active SORT.
-
RETURN only in OUTPUT PROCEDURE: The RETURN statement is valid only within the OUTPUT PROCEDURE of the active SORT or MERGE.
-
SD files cannot be OPENed: Never issue OPEN or CLOSE for a sort/merge work file.
-
MERGE input must be pre-sorted: Unlike SORT, MERGE assumes input files are already in the specified key order.
⚠️ Compiler Behavior Varies: Some COBOL compilers enforce these restrictions at compile time, others at runtime, and some not at all. Code that violates these rules may appear to work on one platform and fail mysteriously on another. Follow the rules regardless of what your specific compiler allows.
15.14 GnuCOBOL Sort Considerations
For students using GnuCOBOL in the Student Mainframe Lab, the SORT verb works but with some differences from Enterprise COBOL:
-
No external sort utility: GnuCOBOL uses its own internal sort algorithm. There are no SORTWK DD statements — the SELECT for the sort file typically uses a temporary file path.
-
ASSIGN clause: Instead of SORTWK01, use a file system path:
cobol SELECT SORT-FILE ASSIGN TO "/tmp/sortwork".Or on Windows:cobol SELECT SORT-FILE ASSIGN TO "C:\TEMP\SORTWORK". -
No FASTSRT: This compiler option is Enterprise COBOL-specific.
-
Performance: For most student-scale datasets (thousands of records), GnuCOBOL's sort performance is more than adequate. For production-scale datasets (millions of records), mainframe sort utilities are dramatically faster.
-
SORT-RETURN: GnuCOBOL supports the SORT-RETURN special register, so your error-handling code is portable.
🧪 Try It Yourself: Compile and run the SORT-SIMPLE program from Section 15.3.1 using GnuCOBOL. Create a test input file with at least 50 records and verify the output is correctly sorted. Then modify it to use an INPUT PROCEDURE that filters out records with negative amounts.
15.15 Common Sort Patterns in Practice
15.15.1 Pattern: Sort-Match-Update
The most common use of SORT in batch processing is the sort-match-update pattern:
- Sort the transaction file on the same key as the master file
- Match transaction records against master records sequentially
- Update the master file with matching transactions
[Unsorted Transactions] → SORT → [Sorted Transactions]
↓
MATCH with [Master File]
↓
[Updated Master File]
This pattern is fundamental to batch processing and appears in nearly every mainframe application.
15.15.2 Pattern: Sort-Dedup
Sort records to bring duplicates together, then eliminate duplicates in the OUTPUT PROCEDURE:
SORT SORT-FILE
ON ASCENDING KEY SR-FULL-KEY
USING RAW-INPUT
OUTPUT PROCEDURE IS 5000-DEDUP
15.15.3 Pattern: Sort-Split
Sort a file and then split it into multiple output files based on record content:
2000-SPLIT-OUTPUT.
OPEN OUTPUT DEPOSIT-FILE
OPEN OUTPUT WITHDRAWAL-FILE
OPEN OUTPUT TRANSFER-FILE
PERFORM 2100-GET-AND-SPLIT
UNTIL EOF-SORT
CLOSE DEPOSIT-FILE
WITHDRAWAL-FILE
TRANSFER-FILE.
2100-GET-AND-SPLIT.
RETURN SORT-FILE INTO WS-WORK-REC
AT END
SET EOF-SORT TO TRUE
NOT AT END
EVALUATE WW-TXN-TYPE
WHEN 'D'
WRITE DEPOSIT-REC
FROM WS-WORK-REC
WHEN 'W'
WRITE WITHDRAWAL-REC
FROM WS-WORK-REC
WHEN 'T'
WRITE TRANSFER-REC
FROM WS-WORK-REC
END-EVALUATE
END-RETURN.
15.15.4 Pattern: Sort-Aggregate
Sort records and produce summary records (aggregating by key):
3000-AGGREGATE-OUTPUT.
OPEN OUTPUT SUMMARY-FILE
PERFORM 3050-INIT-FIRST
PERFORM 3100-AGGREGATE-LOOP
UNTIL EOF-SORT
PERFORM 3200-WRITE-FINAL-SUMMARY
CLOSE SUMMARY-FILE.
15.16 Putting It All Together: A Production Sort Program Checklist
Based on Maria Chen's production standards at GlobalBank, here is a checklist for any sort program:
✅ Before the SORT: - Validate that input files exist and are accessible - Log the start of the sort with timestamp - Set any required sort options (SORT-RETURN initialization)
✅ In the INPUT PROCEDURE: - Validate every record before RELEASEing - Count records read, released, and rejected - Write rejected records to an error/exception file with reason codes - Implement an error threshold — abort if too many records fail - Handle AT END properly
✅ In the OUTPUT PROCEDURE: - Handle the first record specially (initialize control break fields) - Count records written - Handle all edge cases (empty file, single record, etc.) - Verify expected record counts match actual counts
✅ After the SORT: - Check SORT-RETURN - Display/log all record counts for reconciliation - Set appropriate RETURN-CODE for JCL condition checking - Log the end of the sort with timestamp and elapsed time
⚖️ The Human Factor: Priya Kapoor observes: "The sort itself rarely fails — our sort utility has been rock-solid for decades. What fails is the data. Bad records, truncated files, wrong file delivered to the wrong job — that is what brings the batch cycle down. Every line of validation in your INPUT PROCEDURE is insurance against a 3 AM phone call."
15.17 Multi-Key Sort Strategies
Sorting on multiple keys is common in production systems, but the interaction between keys, their data types, and their sort directions creates subtleties that deserve careful attention.
15.17.1 Key Priority and Declaration Order
When multiple sort keys are declared, the first key listed is the major key and the last is the minor key. The sort orders records by the major key first; only when two records have identical major keys does the minor key determine order:
SORT SORT-FILE
ON ASCENDING KEY SR-REGION *> Major
ON ASCENDING KEY SR-BRANCH *> Intermediate
ON DESCENDING KEY SR-AMOUNT *> Minor
USING TRANS-IN
GIVING TRANS-OUT
This produces output grouped by region, then by branch within each region, and within each branch the transactions appear in descending amount order (largest first). Understanding this hierarchy is essential for downstream programs that rely on the sort order for control-break processing.
15.17.2 Mixed Ascending and Descending Keys
Mixing sort directions is powerful for reporting scenarios. For example, MedClaim needs claims sorted by provider (ascending) and then by charge amount (descending) to identify the highest-cost claims for each provider first:
SORT SORT-FILE
ON ASCENDING KEY SC-PROVIDER-NUM
ON DESCENDING KEY SC-CHARGE-AMT
ON ASCENDING KEY SC-CLAIM-DATE
WITH DUPLICATES IN ORDER
USING CLAIMS-IN
GIVING CLAIMS-OUT
Within each provider, claims appear from most expensive to least expensive. When two claims for the same provider have the same charge amount, they are further ordered by claim date (ascending). WITH DUPLICATES IN ORDER ensures that if all three keys match, the original file order is preserved.
15.17.3 Sorting on Packed Decimal Keys
When a sort key is COMP-3 (packed decimal), the sort utility must know the field's representation to compare values correctly. COBOL communicates this through the SD record layout. A common mistake is declaring the sort key as PIC X (alphanumeric) in the SD when the actual data is COMP-3:
*--- WRONG: Sort key declared as alphanumeric ---
SD SORT-WORK.
01 SORT-REC.
05 SR-ACCT-NUM PIC X(10).
05 SR-AMOUNT PIC X(06). *> WRONG for COMP-3!
05 FILLER PIC X(84).
*--- CORRECT: Sort key declared with proper USAGE ---
SD SORT-WORK.
01 SORT-REC.
05 SR-ACCT-NUM PIC X(10).
05 SR-AMOUNT PIC S9(9)V99 COMP-3. *> Correct
05 FILLER PIC X(84).
If the sort key is declared as alphanumeric, the sort utility compares bytes left to right using the collating sequence, which is not the same as numeric comparison for packed decimal. Negative amounts, in particular, will sort incorrectly because the sign nibble (X'D' for negative) is a higher hex value than X'C' (positive). Derek Washington once spent a day debugging a sort that placed all negative transactions after positive ones because the SD declared the amount field as PIC X.
15.17.4 Composite Keys via Concatenation
Sometimes you need to sort on a key that does not exist as a single field in the record. You can construct composite keys in an INPUT PROCEDURE:
SD SORT-WORK.
01 SORT-REC.
05 SR-COMPOSITE-KEY PIC X(18).
05 SR-ORIG-DATA PIC X(82).
1000-BUILD-COMPOSITE-KEY.
OPEN INPUT RAW-FILE
PERFORM 1100-PROCESS-INPUT UNTIL EOF-INPUT
CLOSE RAW-FILE.
1100-PROCESS-INPUT.
READ RAW-FILE INTO WS-INPUT-REC
AT END SET EOF-INPUT TO TRUE
NOT AT END
STRING WI-REGION DELIMITED BY SIZE
WI-DATE DELIMITED BY SIZE
INTO SR-COMPOSITE-KEY
MOVE WS-INPUT-REC TO SR-ORIG-DATA
RELEASE SORT-REC
END-READ.
This creates a sort key by concatenating region and date, allowing the sort to order by both fields as a single comparison. The OUTPUT PROCEDURE then extracts the original data from SR-ORIG-DATA.
15.17.5 Performance Implications of Key Count and Position
📊 Sort Performance by Key Configuration:
| Key Configuration | Relative Time | Notes |
|---|---|---|
| Single key at offset 0 | 1.00x (baseline) | Optimal — sort utility may use fast path |
| Single key at offset 50 | 1.02x | Minimal overhead for key extraction |
| Three ascending keys at offset 0 | 1.05x | Key comparison slightly longer |
| Three mixed-direction keys | 1.08x | Descending keys may require transformation |
| Five keys with COMP-3 | 1.12x | Packed decimal comparison adds cycles |
These differences are negligible for small files but can be significant when sorting 50+ million records during the nightly batch window.
15.18 Sort Performance Benchmarking
In production environments, sort performance directly affects batch window completion. Understanding how to benchmark and optimize sorts is a practical skill.
15.18.1 Measuring Sort Elapsed Time
COBOL provides the ACCEPT FROM TIME facility for simple benchmarking:
01 WS-START-TIME PIC 9(08).
01 WS-END-TIME PIC 9(08).
01 WS-ELAPSED PIC 9(08).
ACCEPT WS-START-TIME FROM TIME
SORT SORT-FILE
ON ASCENDING KEY SR-ACCT-NUM
USING TRANS-IN
GIVING TRANS-OUT
ACCEPT WS-END-TIME FROM TIME
COMPUTE WS-ELAPSED = WS-END-TIME - WS-START-TIME
DISPLAY 'SORT ELAPSED: ' WS-ELAPSED ' HHMMSSCC'
For more precise measurement, DFSORT writes timing information to SYSOUT. The key metrics are:
- INSERT time: Time to accept records into the sort (INPUT PROCEDURE or USING I/O)
- SORT time: Time for the actual sort algorithm
- MERGE time: Time to merge sorted runs
- OUTPUT time: Time to return sorted records (OUTPUT PROCEDURE or GIVING I/O)
15.18.2 Estimating Sort Resource Requirements
Before running a large sort in production, estimate the resource requirements:
Records: 10,000,000
Record length: 200 bytes
Total data: 10M * 200 = 2 GB
Sort work space: Typically 2-3x the data size
Estimate: 4-6 GB across sort work datasets
Memory: More memory = fewer merge passes
Ideal: enough to hold all data in memory
For 2 GB: request at least 512 MB
Estimated time: DFSORT on z15: ~2 GB/min throughput
Estimate: ~1 minute for sort phase
Add I/O time for input and output
Maria Chen maintains a spreadsheet of sort performance baselines for every major batch job. When a sort takes 20% longer than its baseline, operations automatically investigates — it might indicate a data volume increase, an I/O contention issue, or a system configuration change.
15.18.3 DFSORT ICETOOL for Analysis
DFSORT's ICETOOL utility provides powerful analysis capabilities that complement COBOL's SORT:
//ANALYZE EXEC PGM=ICETOOL
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//IN1 DD DSN=PROD.TRANS.SORTED,DISP=SHR
//TOOLIN DD *
COUNT FROM(IN1) EMPTY
STATS FROM(IN1) ON(45,6,PD) TITLE('AMOUNT STATISTICS')
UNIQUE FROM(IN1) ON(1,10,CH) TITLE('UNIQUE ACCOUNTS')
/*
This tells you: the file's record count, statistics (min, max, average, total) on the packed decimal amount field at offset 45, and the number of unique account numbers. These metrics help verify sort correctness and are invaluable for operations monitoring.
🧪 Try It Yourself: Create a sort program that processes at least 1,000 records with three sort keys (one descending). Add timing instrumentation using ACCEPT FROM TIME before and after the SORT. Run the program, then modify it to use INPUT PROCEDURE filtering (remove 30% of records) and compare the elapsed time. Is the filtered sort faster? By how much?
15.19 External Sort Integration: COBOL and JCL Working Together
In production mainframe environments, SORT operations rarely exist in isolation. They are part of multi-step JCL jobs where the sort interacts with preceding and following steps. Understanding this integration is essential for production COBOL developers.
15.19.1 Typical Production Sort Job Stream
A complete nightly batch cycle at GlobalBank might look like this:
//*=========================================================
//* STEP010: Extract today's transactions from DB2
//*=========================================================
//STEP010 EXEC PGM=GBEXT01
//RAWFILE DD DSN=WORK.TXN.RAW.DAILY,DISP=(NEW,CATLG),
// SPACE=(CYL,(100,20)),UNIT=SYSDA
//*=========================================================
//* STEP020: Sort and validate transactions (COBOL SORT)
//*=========================================================
//STEP020 EXEC PGM=GBSORT01,COND=(4,LT,STEP010)
//TXNIN DD DSN=WORK.TXN.RAW.DAILY,DISP=SHR
//TXNOUT DD DSN=WORK.TXN.SORTED.DAILY,DISP=(NEW,CATLG),
// SPACE=(CYL,(100,20)),UNIT=SYSDA
//ERRFILE DD DSN=WORK.TXN.ERRORS.DAILY,DISP=(NEW,CATLG),
// SPACE=(CYL,(5,2)),UNIT=SYSDA
//SORTWK01 DD SPACE=(CYL,(50,10)),UNIT=SYSDA
//SORTWK02 DD SPACE=(CYL,(50,10)),UNIT=SYSDA
//SORTWK03 DD SPACE=(CYL,(50,10)),UNIT=SYSDA
//*=========================================================
//* STEP030: Apply sorted transactions to master file
//*=========================================================
//STEP030 EXEC PGM=GBUPD01,COND=(4,LT,STEP020)
//TXNIN DD DSN=WORK.TXN.SORTED.DAILY,DISP=SHR
//MASTER DD DSN=PROD.ACCT.MASTER,DISP=OLD
Key observations:
-
SORTWK datasets: Three sort work datasets provide parallelism for the sort utility. More work datasets generally improve performance for large sorts.
-
COND parameter: STEP030 runs only if STEP020 completed with a return code less than 4. This is the production safety net — if the sort fails or detects too many errors, downstream processing stops.
-
Separate error file: The ERRFILE captures rejected records for manual review. Operations monitors check this file's record count each morning.
15.19.2 Coordinating Sort Return Codes with JCL
The RETURN-CODE special register (set by the COBOL program) flows to the JCL COND parameter. A well-designed sort program uses a tiered return code scheme:
*--- Set return code based on results ---
EVALUATE TRUE
WHEN SORT-RETURN NOT = ZERO
MOVE 16 TO RETURN-CODE
DISPLAY 'SORT FAILED - RC 16'
WHEN WS-ERROR-PCT > 5
MOVE 12 TO RETURN-CODE
DISPLAY 'HIGH ERROR RATE - RC 12'
WHEN WS-ERROR-PCT > 1
MOVE 8 TO RETURN-CODE
DISPLAY 'MODERATE ERRORS - RC 8'
WHEN WS-ERROR-CNT > 0
MOVE 4 TO RETURN-CODE
DISPLAY 'MINOR ERRORS - RC 4'
WHEN OTHER
MOVE 0 TO RETURN-CODE
DISPLAY 'CLEAN RUN - RC 0'
END-EVALUATE
Downstream JCL steps check these return codes:
//* Run only if sort was clean or had minor errors
//STEP030 EXEC PGM=GBUPD01,COND=(8,LE,STEP020)
This means: skip STEP030 if STEP020's return code is greater than or equal to 8. So the update runs only when the sort returned 0 or 4 (clean or minor errors).
15.19.3 Pre-Sort Verification with IDCAMS
Before running a COBOL sort, production jobs often verify the input file exists and is not empty:
//* Verify input file has records
//VERIFY EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
PRINT INFILE(INDD) COUNT(1)
/*
//INDD DD DSN=WORK.TXN.RAW.DAILY,DISP=SHR
If the file is empty or missing, IDCAMS returns a non-zero code and the sort step is skipped. This prevents the sort program from running against empty input and producing confusing results.
15.20 Chapter Summary
In this chapter, we explored the COBOL SORT and MERGE verbs — the workhorses of batch data processing. We covered:
- The SORT verb with its SD entry, sort key specifications, and ASCENDING/DESCENDING options
- USING and GIVING for simple, declarative sorts with no transformation
- INPUT PROCEDURE with RELEASE for filtering and transforming records before sorting
- OUTPUT PROCEDURE with RETURN for processing sorted records
- The MERGE verb for combining pre-sorted files efficiently
- Error handling through SORT-RETURN and the error threshold pattern
- External sort utilities (DFSORT, SyncSort) and when to use JCL sort vs. COBOL SORT
- Performance tuning including FASTSRT, sort work space allocation, and tag sorts
- Common patterns including sort-match-update, sort-dedup, sort-split, and sort-aggregate
The SORT verb exemplifies COBOL's philosophy of declarative power: you specify what to sort and how to order it, and the runtime's sort utility — the product of decades of optimization — handles the rest. When you need more control, INPUT and OUTPUT PROCEDUREs let you inject your business logic into the sort pipeline without sacrificing the performance of the underlying sort engine.
In the next chapter, we turn to Report Writer — another declarative facility that lets COBOL handle the mechanics of page formatting, control breaks, and totaling while you focus on what the report should contain.
Key Terms Introduced in This Chapter
| Term | Definition |
|---|---|
| SD (Sort Description) | A file description for sort work files, analogous to FD for regular files |
| SORT verb | COBOL verb that arranges file records in a specified key order |
| MERGE verb | COBOL verb that interleaves records from pre-sorted files |
| RELEASE | Statement that passes a record to the sort within an INPUT PROCEDURE |
| RETURN | Statement that retrieves a sorted record within an OUTPUT PROCEDURE |
| INPUT PROCEDURE | User-written code that supplies records to the sort |
| OUTPUT PROCEDURE | User-written code that processes sorted records |
| SORT-RETURN | Special register containing the sort's return code |
| FASTSRT | Compiler option allowing the sort utility to bypass COBOL I/O |
| Tag sort | Technique of sorting keys separately from full records for performance |
| Stable sort | A sort that preserves the relative order of records with equal keys |
| Sort work file | Temporary file used by the sort utility during the sort process |