|
10. The COBOL Sort
SORTEX1.
This does what is known as an internal sort, I.E., the COBOL program does the sorting. The program reads an input file; while holding it in memory it sorts the records. Then it writes out the sorted records to a new output file. The suggested logic avoids misunderstandings engendered by the use of sections. It is compatible with the latest version of COBOL. (An older version of COBOL, VS COBOL worked as well, but generated disturbing error messages.) This program uses input and output procedures in which you control the logic flow and can perform input validation and output processing.
There are many ways to sort files. Some applications use a JCL Utility Sort. You’ll have to learn about that in a JCL book or class. I show you here how to do it in COBOL. COBOL and the Utility work together in this one. You write statements in COBOL; COBOL then prepares statements in the way that the Utility wants to see them and passes them to the Utility. It does all the dirty work. You just write COBOL statements in English.
I purposely avoid the debate on which way is better: JCL Utility or COBOL statements. I don’t think its a question of what’s better, but what suits your purpose better. The COBOL sort lets you do anything you want to the unsorted records before sorting them: you can select the ones you want to sort, you can rearrange fields on the record, you can drop fields or add fields. You can do whatever you want to each sorted record as soon as it gets sorted, you can produce a report, do subtotals or use the sorted file as a transaction file in a file update program.
Here is the program SORTEX1:
000100 IDENTIFICATION DIVISION.
000200* Cobol sort. Consistent with COBOL 390
000300* does not use sections; does not use go to
000400* uses sort procedures
000500* does a sort with some minimal input validation
000600* since everything is done in an orderly way,
000700* you can easily add code of your own to this program
000800 PROGRAM-ID. 'SORTEX1'.
000900 ENVIRONMENT DIVISION.
001000 CONFIGURATION SECTION.
001100 INPUT-OUTPUT SECTION.
001200 FILE-CONTROL.
001300* INPUT FILE UNSORTED
001400 SELECT UNSORTED-FILE ASSIGN UNSORTED.
001500* The work file for the sort utility
001600* you need the select and an sd but do not need jcl for it
001700 SELECT SORT-WORK ASSIGN SORTWORK.
001800* output file normally a disk/tape file
001900* for this program, send it to the printer
002000 SELECT SORTED-FILE ASSIGN SORTED.
002100*
002200 DATA DIVISION.
002300 FILE SECTION.
002400*
002500 FD UNSORTED-FILE
002600 RECORDING MODE IS F
002900 RECORD CONTAINS 80 CHARACTERS.
003000
003100 01 UNSORTED-RECORD.
003200 05 WS-UR-ACCT-NO PIC X(5).
003300 05 FILLER PIC X(5).
003400 05 WS-UR-AMOUNT PIC 9(5).
003500 05 WS-UR-CUST-NAME PIC X(10).
003600 05 FILLER PIC X(5).
003700 05 WS-UR-TRANS-CODE PIC X(1).
003800 05 FILLER PIC X(49).
003900
004000 SD SORT-WORK
004400 RECORD CONTAINS 80 CHARACTERS.
004500*
004600 01 SORT-WORK-RECORD.
004700* You need a definition and picture for
004800* the field that is sorted on (sort key)
004900 05 SW-ACCT-NO PIC X(05).
005000* YOU NEED A FILLER TO COMPLETE THE DEFINITION
005100 05 FILLER PIC X(75).
005200*
005300 FD SORTED-FILE
005400 RECORDING MODE IS F
005700 RECORD CONTAINS 80 CHARACTERS.
005800*
005900 01 SORTED-RECORD.
006000 05 WS-SR-ACCT-NO PIC X(05).
006100 05 FILLER PIC X(05).
006200 05 WS-SR-AMOUNT PIC 9(05).
006300 05 WS-SR-CUST-NAME PIC X(10).
006400 05 FILLER PIC X(55).
006500
006600 WORKING-STORAGE SECTION.
006700 01 SWITCHES.
006800 05 UNSORTED-FILE-AT-END PIC X VALUE 'N'.
006900 05 SORT-WORK-AT-END PIC X VALUE 'N'.
007000 05 valid-sw PIC X VALUE 'N'.
007100
007200 01 COUNTERS.
007300 05 RELEASED-COUNTER PIC S9(7)
007400 PACKED-DECIMAL VALUE +0.
007500 05 REJECT-COUNTER PIC S9(7)
007600 PACKED-DECIMAL VALUE +0.
007700
007800 PROCEDURE DIVISION.
007900 PERFORM INITIALIZATION
008000* Compare this logic to that of the simple program
008100* notice how the sort verb replaces the
008200* perform main until end of file etc
008300 SORT SORT-work ASCENDING KEY SW-ACCT-NO
008400 INPUT PROCEDURE SORT-INPUT
008500 OUTPUT PROCEDURE SORT-OUTPUT
008600 PERFORM TERMINATION
008700 GOBACK.
008800
008900 INITIALIZATION.
009000* Do what you normally do in initialization
009100* open the regular input file (not the sort work file)
009200* and other files needed
009300* (you could open them in the sort input procedure, too)
009400 OPEN INPUT UNSORTED-FILE
009500 output SORTED-FILE
009600* READ THE FIRST RECORD ON THE REGULAR INPUT FILE
009700 PERFORM READ-IT.
009800* Whatever else you do in initialization
009900* headers, initialize counters, etc
010000
010100 TERMINATION.
010200* Do what you normally do in termination
010300* print out total lines
010400* close the files you opened
010500* display totals
010600 CLOSE UNSORTED-FILE
010700 SORTED-FILE.
010800
010900 READ-IT.
011000 READ UNSORTED-FILE
011100 AT END MOVE 'Y' TO UNSORTED-FILE-AT-END
011200 END-READ.
011300
011400 SORT-INPUT.
011500* This is the 'sort input procedure'
011600* when control passes thru the last statement in it
011700* the input phase of the sort is finished
011800* and actual sorting takes place
011900 PERFORM SORT-INPUT-PROCESS-ALL
012000 UNTIL UNSORTED-FILE-AT-END = 'Y'.
012100
012200 SORT-INPUT-PROCESS-ALL.
012300* This is the point when you have each unsorted input record
012400* in your hands
012500* many programs do some validation or selection here
012600* to determine which records are actually given to the sort util
012700* we will do some simple validation here
012800 MOVE 'Y' TO VALID-SW
012900 PERFORM SORT-INPUT-VALIDATE
013000 IF VALID-SW = 'Y'
013100 THEN
013200** Give the unsorted input record to the sort utility
013300 RELEASE SORT-work-RECord FROM unsorted-RECORD
013400 ADD 1 TO RELEASED-COUNTER
013500 ELSE
013600** Here, you have decided not to give the unsorted input
013700** record to the sort utility
013800 ADD 1 TO REJECT-COUNTER
013900 END-IF
014000 PERFORM READ-IT.
014100
014200 SORT-INPUT-VALIDATE.
014300* Check the regular input record for validity.
014400* if it is not suitable for sorting, set the valid sw
014500* other validation criteria would apply for other files
014600 IF WS-UR-ACCT-NO IS equal to spaces
014700 THEN MOVE 'N' TO VALID-SW
014800 END-IF.
014900
015000 SORT-OUTPUT.
015100* This is the 'sort output procedure'
015200* when control passes thru the last statement in it
015300* the output phase of the sort is finished
015400* you have seen (returned) the last sorted record
015500* and the sort utility is finished
015600 PERFORM RETURN-IT
015700 PERFORM SORT-OUTPUT-PROCESS-ALL
015800 UNTIL SORT-WORK-AT-END = 'Y'.
015900
016000 RETURN-IT.
016100* Gets each sorted record from the sort utility
016200* return is logically like a read
016300 RETURN SORT-work
016400 AT END MOVE 'Y' TO SORT-work-AT-END
016500 END-RETURN.
016600
016700 SORT-OUTPUT-PROCESS-ALL.
016800 PERFORM SORT-OUTPUT-PROCESSING
016900 PERFORM RETURN-IT.
017100 SORT-OUTPUT-PROCESSING.
017200* Here you do the things you do in a
017300* regular program's main processing routine
017400* add totals, compute things
017500* write detail records, print lines, etc
017600* you could put control break check here
017700* this program just and writes the record out to "sorted file"
017900 MOVE SORT-WORK-RECORD TO SORTED-RECORD
018100 WRITE SORTED-RECORD.
Here is the input transaction data file UNSORTED: (the next two lines are a column ruler)
1 2 3 4 5 6
123456789.123456789.123456789.123456789.123456789.123456789.12345678
ACCT0 00100 GRUMPY CHANGE TRANSFIL
ACCT8 00100 WIMPY CHANGE TRANSFIL
ACCT1 00100 SNEAZZY ADD TRANSFIL
ACCT1 00100 SNEAZZY ADD TRANSFIL
ACCT1 00100 RUDOLPH CHANGE TRANSFIL
ACCT1 00100 DELETE TRANSFIL
ACCT4 00100 THUMPER ADD TRANSFIL
ACCT5 00100 DELETE TRANSFIL
ACCT7 00100 MR ED ADD TRANSFIL
ACCT8 00100 DONNER CHANGE TRANSFIL
ACCT9 00100 TOTO CHANGE TRANSFIL
Here is sample JCL:
//STEP1 EXEC PGM=SORTEX1
//STEPLIB DD DSN=your.executable.program.library.goes.here,DISP=SHR
//*OF COURSE, THE NEXT LIBRARY NAME MAY BE DIFFERENT AT YOUR COMPANY
//*IT’S POSSIBLE THAT YOU WILL NEED MORE JCL BECAUSE OF THE SORT
//UNSORTED DD DSN=userid.COBBOOK.DATA(UNSORTED),DISP=SHR
//SORTED DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
|