Sort and Merge

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against ISO/IEC 1989:2023 (edition 3, January 2023; an upcoming 4th edition is in ballot), in which SORT and MERGE come from COBOL 74 and 85 and the table SORT from COBOL 2002; against IBM Enterprise COBOL for z/OS 6.5 (PTFs through September 2026) on z/OS 3.2, where the statements hand the work to DFSORT or an equivalent product; and against GnuCOBOL 3.2 (28 July 2023, the latest release), which has its own built-in sort, and with which every program on it was compiled with cobc -x -Wall and run on 2026-10-20 (and again with -std=ibm, which printed the same results unless the text says otherwise). z/OS examples are labelled "z/OS; not run here" and are checked against the Language Reference and the Programming Guide.

Sorting puts records in the order of one or more keys, and merging combines files that are already in that order. Batch systems do both constantly: the nightly Circulation run sorts the day’s loan transactions by book before the balance-line update of Sequential Files, and merges the transactions of several branches into one stream. This page covers the SD entry, the SORT statement in its three forms (file with USING/GIVING, file with procedures, and table), RELEASE and RETURN, MERGE, the special registers, the z/OS side with FASTSRT, DFSORT control statements and ICETOOL, and the mistakes that sort programs invite. The file statements around it are on File Concepts, SELECT and FD; sorting an in-memory table with SORT table and searching it are on Searching and Sorting Tables; the status codes of the files involved are on File Status Codes.

Where the book is outdated: Taulli’s Modern Mainframe Development (2022, chapter 3) shows sorting only as a DFSORT job in JCL, which is a valid and common approach and is described below. It does not cover the COBOL SORT and MERGE statements at all (no SD, no INPUT PROCEDURE, no RELEASE or RETURN), and neither does chapter 5, so everything about the statements comes from the official manuals. The book’s z/OS 2.4 context is also old; DFSORT is part of z/OS 3.2 with the same control-statement language.

The model: a sort file that is not a file

A sort works on a sort file that the program never opens. The program describes it with an SD (sort description) entry and a SELECT entry, names it in SORT, and the run time provides the work space.

SELECT sort-file ASSIGN TO assignment-name.

SD  sort-file.
01  sort-record.
    05  key-field ...
  • The SELECT entry has no ORGANIZATION or ACCESS clause. The file forms of SORT and MERGE need both the SELECT and the SD; the table form needs no file.

  • The SD entry has no BLOCK CONTAINS, LABEL or FILE STATUS. Its record description defines the fields that can be keys. Using an FD instead of an SD is a compile-time error.

  • On z/OS the work data sets are described by the DFSORT job-step DD statements, for example SORTWK01; modern DFSORT allocates work space dynamically, so the JCL usually needs none.

  • In GnuCOBOL the assignment name is a label and the sort uses temporary files governed by COB_SORT_MEMORY and COB_SORT_CHUNK; no JCL is involved.

The next sections cover the SORT forms in order of increasing control. The diagram shows the flow with procedures, the most general form: records enter the sort one by one through RELEASE in the input procedure, the sort orders them using work files, and the output procedure takes them back one by one with RETURN. USING replaces the input procedure with "read all records of these files", and GIVING replaces the output procedure with "write all records to these files".

flowchart LR A["Input files: LOANDAY"] --> B["INPUT PROCEDURE: READ, validate, RELEASE"] B --> C[("Sort work files")] C --> D["Sort by the keys: book ascending, date descending"] D --> E["OUTPUT PROCEDURE: RETURN, process each record"] E --> F["Report or output file"] A -. "USING replaces the procedure" .-> C D -. "GIVING replaces the procedure" .-> F

SORT with USING and GIVING

The simplest form reads every record of the input files, sorts, and writes the result to the output files:

SORT sort-file
    {ON {ASCENDING | DESCENDING} KEY key-name ...} ...
    [WITH DUPLICATES IN ORDER]
    [COLLATING SEQUENCE IS alphabet-name]
    USING input-file-1 [input-file-2 ...]
    GIVING output-file-1 [output-file-2 ...]
  • Keys. Each KEY names a field of the sort record. They are listed from the most to the least significant, whatever the grouping of ASCENDING and DESCENDING; a keyword applies to all following keys until the next one. A key cannot have an OCCURS clause or be under one, and with variable-length records all keys must lie within the shortest record.

  • Same position in every input. The key must be at the same position and in the same format in the sort record and in every input record.

  • WITH DUPLICATES IN ORDER. Records with equal keys come out in the order of the input files in the USING list and within a file in their input order (or release order, with an input procedure). Without it the order of equal keys is undefined. The balance-line update depends on this: a checkout and a return of the same book must stay in the order in which they happened.

  • COLLATING SEQUENCE. It applies to alphabetic and alphanumeric keys only, and names an alphabet from SPECIAL-NAMES. Without it, the program collating sequence applies; if none is set, Enterprise COBOL uses EBCDIC, and GnuCOBOL the native ASCII.

  • USING and GIVING files are described by FD entries, must be closed when the SORT runs, and are opened, read or written and closed by the run time. The records of a GIVING file are written like a plain WRITE.

The next program sorts the day’s loan transactions by book number and, within a book, by date, keeping the arrival order of equal keys. The SD record is the LOANREC copybook with its prefix renamed to SRT- using COPY ... REPLACING LEADING, so that the keys have their own names.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. LOANSORT.
      * SORT ... USING ... GIVING: order the loans by book, then date.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT LOAN-IN ASSIGN TO "LOANTRAN"
               ORGANIZATION IS LINE SEQUENTIAL.
           SELECT LOAN-OUT ASSIGN TO "LOANSRT"
               ORGANIZATION IS LINE SEQUENTIAL.
           SELECT SORT-FILE ASSIGN TO "SORTWK01".
       DATA DIVISION.
       FILE SECTION.
       FD  LOAN-IN.
       01  LOAN-IN-LINE        PIC X(30).
       FD  LOAN-OUT.
       01  LOAN-OUT-LINE       PIC X(30).
       SD  SORT-FILE.
       COPY LOANREC REPLACING LEADING ==LOAN-== BY ==SRT-==.
       PROCEDURE DIVISION.
       0000-MAIN-LINE.
           SORT SORT-FILE
               ON ASCENDING KEY SRT-BOOK-ID
               ON ASCENDING KEY SRT-DATE
               WITH DUPLICATES IN ORDER
               USING LOAN-IN
               GIVING LOAN-OUT
           DISPLAY "SORT-RETURN = " SORT-RETURN
           STOP RUN.

Compiled with cobc -x -Wall -I. loansort.cob (and with -std=ibm), no warnings, it prints:

SORT-RETURN = +000000000

and LOANSRT holds the four transactions in book order (the sorted file that the balance-line update reads):

O00010000000120261020
R00010000000120261020
O00010100000220261020
O00010200000320261020

The two transactions of book 1 kept their arrival order. SORT-RETURN is a special register that holds 0 after a successful sort; GnuCOBOL shows it as a signed number. The key names are checked at compile time: a key that is not in the sort record is reported by cobc, and an FD used where an SD is required is rejected.

bad1.cob:17: error: 'SRT-NOKEY' is not defined
bad1.cob:8: error: must be an SD filename

INPUT PROCEDURE and OUTPUT PROCEDURE

A procedure replaces the automatic read or write when the program has to do something to each record: drop or fix records before sorting, build a record from several sources, or print directly from the sorted stream.

SORT sort-file ON ASCENDING KEY key-name ...
    INPUT PROCEDURE IS section-or-paragraph [THRU end-name]
    OUTPUT PROCEDURE IS section-or-paragraph [THRU end-name]
  • The input procedure reads from any file it likes, and passes each record to the sort with RELEASE sort-record [FROM identifier]. It may release zero records, one per input record, or many. It must not execute a SORT, a MERGE or a RETURN.

  • The output procedure takes the sorted records one by one with RETURN sort-file [INTO identifier] AT END ... [NOT AT END ...] END-RETURN. AT END is required in the statement and runs when there are no more records. It must not execute a SORT, a MERGE or a RELEASE.

  • Control leaves the input procedure through the end of its last paragraph or section, and the sort starts. The sort ends when the output procedure runs off its end, and the program continues after the SORT. Do not STOP RUN or GO TO out of the range.

  • RELEASE and RETURN name the record of the sort file, as WRITE names a record; FROM and INTO do the moves.

  • The range is the section or the THRU range, executed from the first statement to the last. Everything physically inside it runs, as the next example shows.

The following program takes the transactions of the next day in LOANDAY, which contains two bad records: type X and a non-numeric book number. The input procedure releases only valid records (O or R with numeric ids); the output procedure shows them in book order and, within a book, newest date first.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. LOANPROC.
      * SORT with INPUT PROCEDURE (validate, RELEASE) and OUTPUT
      * PROCEDURE (RETURN, count transactions per book).
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT LOAN-IN ASSIGN TO "LOANDAY"
               ORGANIZATION IS LINE SEQUENTIAL.
           SELECT SORT-FILE ASSIGN TO "SORTWK01".
       DATA DIVISION.
       FILE SECTION.
       FD  LOAN-IN.
       01  LOAN-IN-LINE        PIC X(30).
       SD  SORT-FILE.
       COPY LOANREC REPLACING LEADING ==LOAN-== BY ==SRT-==.
       WORKING-STORAGE SECTION.
       COPY LOANREC.
       01  WS-EOF-IN           PIC X VALUE "N".
           88  END-OF-INPUT    VALUE "Y".
       01  WS-EOF-SORT         PIC X VALUE "N".
           88  END-OF-SORTED   VALUE "Y".
       01  WS-RELEASED         PIC 9(3) VALUE ZERO.
       01  WS-REJECTED         PIC 9(3) VALUE ZERO.
       01  WS-PREV-BOOK        PIC 9(6) VALUE ZERO.
       01  WS-BOOK-COUNT       PIC 9(3) VALUE ZERO.
       PROCEDURE DIVISION.
       0000-MAIN-LINE.
           SORT SORT-FILE
               ON ASCENDING KEY SRT-BOOK-ID
               ON DESCENDING KEY SRT-DATE
               WITH DUPLICATES IN ORDER
               INPUT PROCEDURE IS 1000-SELECT-LOANS
               OUTPUT PROCEDURE IS 2000-REPORT-LOANS
           DISPLAY "released " WS-RELEASED ", rejected " WS-REJECTED
               ", SORT-RETURN " SORT-RETURN
           STOP RUN.
       1000-SELECT-LOANS SECTION.
       1000-START.
           OPEN INPUT LOAN-IN
           PERFORM UNTIL END-OF-INPUT
               READ LOAN-IN INTO LOAN-RECORD
                   AT END SET END-OF-INPUT TO TRUE
                   NOT AT END PERFORM 1100-VALIDATE
               END-READ
           END-PERFORM
           CLOSE LOAN-IN.
       1000-EXIT.
           EXIT.
       1100-VALIDATE SECTION.
           IF (LOAN-CHECKOUT OR LOAN-RETURN)
              AND LOAN-MEMBER-ID IS NUMERIC
              AND LOAN-BOOK-ID IS NUMERIC
               RELEASE SRT-RECORD FROM LOAN-RECORD
               ADD 1 TO WS-RELEASED
           ELSE
               DISPLAY "rejected: " LOAN-RECORD(1:21)
               ADD 1 TO WS-REJECTED
           END-IF.
       2000-REPORT-LOANS SECTION.
       2000-START.
           PERFORM UNTIL END-OF-SORTED
               RETURN SORT-FILE
                   AT END SET END-OF-SORTED TO TRUE
                   NOT AT END PERFORM 2100-SHOW-LOAN
               END-RETURN
           END-PERFORM.
       2000-EXIT.
           EXIT.
       2100-SHOW-LOAN SECTION.
           DISPLAY "book " SRT-BOOK-ID " " SRT-DATE " " SRT-TYPE
               " member " SRT-MEMBER-ID.

Compiled with cobc -x -Wall -I. loanproc.cob (and with -std=ibm), no warnings, it prints:

rejected: X00010000000120261021
rejected: O0001AB00000320261021
book 000002 20261021 O member 000101
book 000002 20261020 O member 000101
book 000003 20261021 R member 000102
book 000004 20261021 O member 000100
released 004, rejected 002, SORT-RETURN +000000000

The two rejects were reported while the input was read, and four of the six records reached the sort. Book 2 appears twice with the later date first, as the DESCENDING KEY SRT-DATE asks. The COPY LOANREC in WORKING-STORAGE supplies the validation record with the LOAN- names (with the 88-level condition names), and the SD has a second copy with the SRT- names; RELEASE ... FROM copies one into the other.

Falling out of the procedure range

The procedures above are sections, and the helper paragraphs 1100-VALIDATE and 2100-SHOW-LOAN are sections too. If instead they were paragraphs placed below the procedure’s EXIT, they would belong to the same section and would run once more after the loop. This is the same program with the helpers as paragraphs; everything else is identical:

       1000-SELECT-LOANS SECTION.
       1000-START.
           ...
       1000-EXIT.
           EXIT.
       1100-VALIDATE.
           IF (LOAN-CHECKOUT OR LOAN-RETURN) ...

The compiler gives no warning. The input procedure ends at the next section header, so 1100-VALIDATE runs after the loop with the record that is still in LOAN-RECORD, and the output procedure does the same with 2100-SHOW-LOAN:

rejected: X00010000000120261021
rejected: O0001AB00000320261021
rejected: O0001AB00000320261021
book 000002 20261021 O member 000101
book 000002 20261020 O member 000101
book 000003 20261021 R member 000102
book 000004 20261021 O member 000100
book 000004 20261021 O member 000100
released 004, rejected 003, SORT-RETURN +000000000

The last record of the input was rejected twice (three rejects instead of two), and the last sorted record was shown twice (book 4 appears twice). The count released 004 is correct because the extra execution of the validation found a bad record. Keep the helpers outside the range: make each one a section of its own, as the correct program does, put them before the procedure, or use THRU with an explicit end paragraph. This applies to every procedure range: PERFORM section and the INPUT PROCEDURE range both run to the end of the section.

COLLATING SEQUENCE

The default order of an alphanumeric key follows the character set: EBCDIC on z/OS, ASCII on most other systems. So with ASCII all capital letters sort before all lower-case ones. A COLLATING SEQUENCE clause names an alphabet defined in SPECIAL-NAMES: STANDARD-1 (ASCII), STANDARD-2 (ISO 646), NATIVE (the machine’s own), EBCDIC, or one built from literals. The program below defines an alphabet in which each letter and its lower-case form have the same position (ALSO), and sorts four names with it:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. COLL.
      * Sort names with an alphabet that ignores case.
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
           ALPHABET NOCASE IS
               "A" ALSO "a", "B" ALSO "b", "C" ALSO "c",
               "D" ALSO "d", "E" ALSO "e", "F" ALSO "f".
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT SORT-FILE ASSIGN TO "SORTWK01".
       DATA DIVISION.
       FILE SECTION.
       SD  SORT-FILE.
       01  SORT-REC            PIC X(8).
       WORKING-STORAGE SECTION.
       01  WS-EOF              PIC X VALUE "N".
           88  END-OF-SORT     VALUE "Y".
       PROCEDURE DIVISION.
       0000-MAIN-LINE.
           SORT SORT-FILE ON ASCENDING KEY SORT-REC
               COLLATING SEQUENCE IS NOCASE
               INPUT PROCEDURE IS 1000-LOAD
               OUTPUT PROCEDURE IS 2000-SHOW
           STOP RUN.
       1000-LOAD SECTION.
           MOVE "beta" TO SORT-REC RELEASE SORT-REC
           MOVE "Alpha" TO SORT-REC RELEASE SORT-REC
           MOVE "delta" TO SORT-REC RELEASE SORT-REC
           MOVE "Charlie" TO SORT-REC RELEASE SORT-REC.
       2000-SHOW SECTION.
           PERFORM UNTIL END-OF-SORT
               RETURN SORT-FILE
                   AT END SET END-OF-SORT TO TRUE
                   NOT AT END DISPLAY SORT-REC
               END-RETURN
           END-PERFORM.

Compiled with cobc -x -Wall -I. coll.cob (and with -std=ibm), no warnings, it prints the names in alphabetical order regardless of case:

Alpha
beta
Charlie
delta

With the default ASCII order the result would be Alpha, Charlie, beta, delta. The clause affects alphabetic and alphanumeric keys only; numeric keys are compared by value. Accented characters and locale-dependent order need the locale features described on National, UTF-8 and Code Pages.

MERGE

MERGE combines two or more files that are already in the key order:

MERGE merge-file
    {ON {ASCENDING | DESCENDING} KEY key-name ...} ...
    [COLLATING SEQUENCE IS alphabet-name]
    USING input-file-1 input-file-2 [input-file-3 ...]
    {GIVING output-file ... |
     OUTPUT PROCEDURE IS section-or-paragraph [THRU end-name]}
  • There is no input procedure: the inputs are read as they are. At least two USING files are needed.

  • The records of each input file must already be in the key order of the MERGE; the statement does not check it. Out-of-order input gives out-of-order output.

  • With equal keys, the records of the first USING file come first, then those of the second, and so on. WITH DUPLICATES IN ORDER is the behaviour of MERGE, so the clause is not needed.

  • MERGE uses an SD, like SORT.

Two branches send their sorted loans of the day, LOANA (books 1 and 3) and LOANB (books 2, 3 and 4). The merge writes one file in book order:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. LOANMERGE.
      * MERGE two branch files that are already in book order.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT BRANCH-A ASSIGN TO "LOANA"
               ORGANIZATION IS LINE SEQUENTIAL.
           SELECT BRANCH-B ASSIGN TO "LOANB"
               ORGANIZATION IS LINE SEQUENTIAL.
           SELECT LOAN-ALL ASSIGN TO "LOANALL"
               ORGANIZATION IS LINE SEQUENTIAL.
           SELECT MERGE-FILE ASSIGN TO "MERGEWK".
       DATA DIVISION.
       FILE SECTION.
       FD  BRANCH-A.
       01  BRANCH-A-LINE       PIC X(30).
       FD  BRANCH-B.
       01  BRANCH-B-LINE       PIC X(30).
       FD  LOAN-ALL.
       01  LOAN-ALL-LINE       PIC X(30).
       SD  MERGE-FILE.
       COPY LOANREC REPLACING LEADING ==LOAN-== BY ==MRG-==.
       PROCEDURE DIVISION.
       0000-MAIN-LINE.
           MERGE MERGE-FILE
               ON ASCENDING KEY MRG-BOOK-ID
               USING BRANCH-A BRANCH-B
               GIVING LOAN-ALL
           DISPLAY "SORT-RETURN = " SORT-RETURN
           STOP RUN.

Compiled with cobc -x -Wall -I. loanmerge.cob (and with -std=ibm), no warnings, it prints SORT-RETURN = +000000000 and writes LOANALL:

O00010000000120261020
O00010100000220261020
O00010200000320261020
R00010200000320261021
O00010000000420261020

The two records of book 3 are in file order: the checkout from branch A first, then the return from branch B. Merging is linear (each input is read once) and needs no work files beyond the buffers, so it is much cheaper than a sort of the concatenated files, which is why a nightly job sorts each branch in parallel and merges the results.

SORT-RETURN and other special registers

  • SORT-RETURN holds the completion code of the last SORT or MERGE: 0 for success and 16 for failure. Moving 16 to it in an input or output procedure stops the sort. The register is a binary signed number; GnuCOBOL displays it as +000000000.

  • A failure does not abend by itself. Test the register after every SORT and MERGE.

  • On z/OS, SORT-CONTROL names the DD that holds DFSORT control statements (default IGZSRTCD), and SORT-CORE-SIZE, SORT-FILE-SIZE, SORT-MESSAGE and SORT-MODE-SIZE correspond to keywords of that control data set. They are set before the SORT. GnuCOBOL has SORT-RETURN and ignores the others.

A real failure on GnuCOBOL 3.2.0: the USING file was left open by the program (OPEN INPUT LOAN-IN before the SORT). The sort cannot open it, SORT-RETURN is 16, and the output file is not produced:

SORT-RETURN = +000000016
status 00
libcob: warning: implicit CLOSE of LOAN-IN ('LOANTRAN')

The status 00 is the status of the program’s own earlier OPEN, not of the sort. The USING and GIVING files must be closed when the SORT starts.

Sorting a table

COBOL 2002 added a third form that sorts a table in storage, with no file at all:

SORT table-name ON {ASCENDING | DESCENDING} KEY key-name ...
    [WITH DUPLICATES IN ORDER]
    [COLLATING SEQUENCE IS alphabet-name]

The table must have an OCCURS clause. The keys must be the table item or a field inside it, and the sorted elements go back to the same table. Enterprise COBOL supports it (even with the THREAD option, unlike the file form), GnuCOBOL supports it too, and it is covered with examples on Searching and Sorting Tables.

Sorting on z/OS: DFSORT, FASTSRT and the restrictions

In Enterprise COBOL the SORT and MERGE statements call DFSORT (or an equivalent such as SyncSort), which must be available at run time. Several points are specific to that engine:

  • FASTSRT. With the FASTSRT compiler option, DFSORT itself performs the I/O on the USING and GIVING files instead of Enterprise COBOL, which is faster for most sorts. The files must meet the conditions for it that the Programming Guide lists. Without FASTSRT the sort does not check for errors on opening, closing and I/O of those files, so the program should test SORT-RETURN.

  • No SORT under z/OS UNIX. A program containing SORT or MERGE cannot run under z/OS UNIX, including through BPXBATCH, cannot be compiled with THREAD (the table form can), and cannot directly or indirectly call code that needs z/OS UNIX services or threads, such as a JVM.

  • The conventional technique is not supported: with NOBLKSET, with tape for intermediate storage, or with L5 in the DFSORT RECORD option.

  • Work space. DFSORT allocates work data sets dynamically in current installations. Sort work DD statements in the JCL (SORTWKnn) are still honoured.

  • In an output procedure the sorted records come only through RETURN; a READ of the sort file is not allowed.

DFSORT and ICETOOL as an alternative to a COBOL sort

Sorting a file does not need a COBOL program. DFSORT is a utility that a job step runs directly with control statements; for plain ordering, selecting and reformatting it beats a program in length and nearly always in speed. The Circulation job can sort the transactions and keep only checkouts and returns in one step (z/OS; not run here):

//SORTSTEP EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DISP=SHR,DSN=USERID.CIRC.LOANTRAN
//SORTOUT  DD DSN=USERID.CIRC.LOANSRT,DISP=(NEW,CATLG,DELETE),
//            RECFM=FB,LRECL=30,SPACE=(TRK,(5,1))
//SYSIN    DD *
  SORT FIELDS=(8,6,ZD,A,14,8,ZD,A),EQUALS
  INCLUDE COND=(1,1,CH,EQ,C'O',OR,1,1,CH,EQ,C'R')
/*
  • SORT FIELDS=(8,6,ZD,A,14,8,ZD,A) sorts on the six-digit zoned decimal at position 8 (the book number in LOANREC) and then on the eight digits at position 14 (the date), both ascending. Positions are bytes from 1, as in the copybook (LOAN-TYPE at 1, member at 2, book at 8, date at 14).

  • EQUALS keeps records with equal keys in their input order, the counterpart of WITH DUPLICATES IN ORDER.

  • INCLUDE COND=... drops every record whose type is neither O nor R; OMIT does the opposite. OUTREC FIELDS=(...) or OUTFIL can reformat or split the output, and SUM FIELDS=NONE removes duplicates.

ICETOOL is the front end for DFSORT that runs several operations in one step, each one reading and writing named DDs. This step sorts with the same control statements, and counts the records of the input (z/OS; not run here):

//TOOLRUN  EXEC PGM=ICETOOL
//TOOLMSG  DD SYSOUT=*
//DFSMSG   DD SYSOUT=*
//IN       DD DISP=SHR,DSN=USERID.CIRC.LOANTRAN
//OUT      DD DSN=USERID.CIRC.LOANSRT,DISP=(NEW,CATLG,DELETE),
//            RECFM=FB,LRECL=30,SPACE=(TRK,(5,1))
//CTL1CNTL DD *
  SORT FIELDS=(8,6,ZD,A,14,8,ZD,A),EQUALS
/*
//TOOLIN   DD *
  COUNT FROM(IN)
  SORT FROM(IN) TO(OUT) USING(CTL1)
/*

The choice between a COBOL sort and DFSORT:

COBOL SORT DFSORT or ICETOOL step

Best for

Validation or reformatting that needs program logic in the input or output procedure; sorting inside a program that goes on to use the result

Plain order, filter, reformat, merge, join, count and report steps between programs

Cost

A program to write, compile and maintain

A few control statements in the JCL

Failure handling

SORT-RETURN tested by the program

The step return code (COND or IF in the JCL)

Portability

Runs, with different sort engines, on z/OS and with GnuCOBOL

z/OS only (equivalents are sort and awk on Unix)

On the PC the counterpart of the first step is the shell command used on the sequential files page (sort -s -k1.8,1.13 LOANTRAN > LOANSRT), where -s is the stable sort that keeps equal keys in input order.

GnuCOBOL’s built-in sort

GnuCOBOL does not call an external sort program. SORT and MERGE run inside the run-time library, with the records in memory and in temporary files. Settings are environment variables or entries in the run-time configuration:

  • COB_SORT_MEMORY is the memory used before it spills to disk, and COB_SORT_CHUNK the chunk size of the temporary files (see the run-time configuration chapter of the manual for the defaults and units).

  • SORT-RETURN is set as in the standard. The extra Enterprise COBOL special registers for DFSORT are not needed with the built-in sort and were not tested here.

  • WITH DUPLICATES IN ORDER is honoured, as the examples above show; without it GnuCOBOL’s order of equal keys must not be relied on.

  • Records with trailing spaces trimmed in LINE SEQUENTIAL files are padded when read, so a key defined at the end of a short line sees spaces.

Common mistakes

  • Opening the USING or GIVING file before the SORT. The sort cannot open it and fails with SORT-RETURN 16; close it first.

  • Unsorted input to MERGE. The output is not sorted and no message is given.

  • Leaving out WITH DUPLICATES IN ORDER. Transactions with the same key come out in any order, which turns a checkout followed by a return into a return followed by a checkout.

  • Helper paragraphs inside a procedure section. They run once more after the loop; make them sections or place them outside the range.

  • A key that moves with the record. A key under an OCCURS entry, or at a different position in different input files, is invalid.

  • Forgetting the case and collating sequence. ASCII and EBCDIC order differ (ASCII: digits, capitals, lower-case; EBCDIC: lower-case, capitals, digits), so a sorted file can change order when it moves between platforms.

  • Not testing SORT-RETURN. A failed sort does not stop the program by itself.

  • Sorting with a SORT statement in a z/OS UNIX or THREAD program. It is not supported; use a DFSORT job step or the table form.

  • Writing a sort program for a plain reordering on z/OS. A DFSORT step with SORT FIELDS= does it with no code.