IEBGENER and DFSORT
Much of a batch night isn't COBOL at all. Copying, sorting, selecting and de-duplicating datasets is done by IBM utilities driven by a few control statements. Knowing them saves you writing a program for every little job.
IEBGENER: copy a dataset
//BACKUP EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSIN DD DUMMY
//SYSUT1 DD DSN=BANK.CUST.MASTER,DISP=SHR
//SYSUT2 DD DSN=BANK.CUST.BACKUP,DISP=(NEW,CATLG,DELETE)
SYSUT1 in, SYSUT2 out, SYSPRINT for messages, SYSIN DD DUMMY
because we want a plain copy. Point SYSUT2 at SYSOUT=* and the same
step prints a dataset: that's how most batch reports reach the spool.
DFSORT: sort, select, de-duplicate
PGM=SORT runs IBM's DFSORT (or its competitor Syncsort, which
accepts the same statements). The DD names are fixed:
| DD | Purpose |
|---|---|
SORTIN |
Input |
SORTOUT |
Output |
SYSIN |
Control statements |
SYSOUT |
DFSORT's messages |
Control statements start in column 2 or later (column 1 is for labels), usually indented by two.
SORT FIELDS
SORT FIELDS=(29,4,CH,A,34,9,ZD,D)
Each key is start,length,format,order. Positions count from 1, like the columns of the record layout table. Formats you'll use daily:
CH: characters, compared byte by byte.ZD: zoned decimal, aPIC 9field stored as digits, compared as a number (so a sign is respected).PD: packed decimal (COMP-3), andBI: binary (COMP), on real systems. The simulator supportsCH,ZDandBI.
SORT FIELDS=COPY copies without sorting, which is useful with INCLUDE.
INCLUDE and OMIT
INCLUDE COND=(33,1,CH,EQ,C'A')
OMIT COND=(29,4,CH,EQ,C'GAL1',OR,34,9,ZD,EQ,0)
Each condition is start,length,format,operator,value, and conditions
join with AND or OR. Operators are the ones from COND: EQ, NE,
GT, GE, LT, LE. Character constants are written C'...',
numbers plainly. INCLUDE keeps matching records; OMIT drops them.
Filtering happens before sorting, so less data gets sorted.
SUM FIELDS=NONE
SORT FIELDS=(1,8,CH,A)
SUM FIELDS=NONE
After sorting, records with equal keys are adjacent. SUM FIELDS=NONE
keeps one per key. (SUM FIELDS=(34,9,ZD) would instead add up that
field across each group, which the simulator doesn't support.)
A complete step
//ACTIVE EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=BANK.CUST.MASTER,DISP=SHR
//SORTOUT DD DSN=BANK.CUST.ACTIVE,DISP=(NEW,CATLG,DELETE)
//SYSIN DD *
INCLUDE COND=(33,1,CH,EQ,C'A')
SORT FIELDS=(29,4,CH,A,34,9,ZD,D)
/*
The step's SYSOUT reports the record counts, the first thing to check
when an output looks short:
ICE054I 0 RECORDS - IN: 7, OUT: 5
ICE052I 0 END OF DFSORT
A mistake in the control statements ends the step with RC 16 and an
ICE...A message instead.
COBOL SORT or DFSORT?
You learned the COBOL SORT verb earlier. If a program only sorts
a file and hands it on, a DFSORT step is simpler, faster and easier
for operations to change. Use the COBOL verb when the sort is tangled
up with program logic in an input or output procedure.
On the job
DFSORT does far more than this: OUTREC and INREC reformat records,
OUTFIL splits one input into several outputs, and ICETOOL builds
reports and counts. Many "can you pull a list of..." requests are
answered with a ten-line sort step, not a new program.
Your task
Build the customer job from utilities only. No COBOL needed.
BANK.CUST.MASTER records (one per customer):
| Field | Positions | Format |
|---|---|---|
| Customer id | 1–8 | CH |
| Name | 9–28 | CH |
| Branch | 29–32 | CH |
| Status | 33 | CH: A active, C closed |
| Balance | 34–42 | ZD, 9(7)V99 |
BACKUP(IEBGENER): copyBANK.CUST.MASTERto a new cataloged datasetBANK.CUST.BACKUP, deleted if the step abends.ACTIVE(SORT): write only the active customers toBANK.CUST.ACTIVE, sorted by branch ascending, and within a branch by balance descending.MAILING(SORT):BANK.MAIL.REQUESTShas one record per statement request (customer id in 1–8, name in 9–28); some customers asked more than once. WriteBANK.MAIL.LISTwith each customer once, in customer id order.
The starter has the start of steps 1 and 2. Every new dataset uses
DISP=(NEW,CATLG,DELETE); inputs are DISP=SHR.