Multiple outputs in DFSORT means writing to more than one dataset or report from a single sort step. Instead of running the sort several times to produce several files, you use multiple OUTFIL statements. Each OUTFIL specifies FNAMES= (the DD name or names where that output is written) and can have its own INCLUDE or OMIT so only certain records go to that file, and its own BUILD= so the record layout can differ per output. You can also list multiple DD names in one FNAMES= (e.g. FNAMES=OUT1,OUT2) to write the same stream to two or more datasets—useful when you need identical copies. Your JCL must define a DD statement for every name used in FNAMES=. This page covers why to use multiple outputs, how to code multiple OUTFILs, FNAMES= with one or many names, order of processing, and how SAVE captures records not selected by earlier OUTFILs.
In batch jobs you often need the same sorted data in more than one place: for example, one file for department A, one for department B, and one for everyone else; or one dataset with full records and another with a short summary for a report; or the same sorted file written to two different DSNs (e.g. production and backup). If you ran a separate SORT step for each output, you would read and sort the input once per step—wasting CPU and time. With multiple OUTFIL statements, you sort once and then, in the output phase, each record is evaluated against each OUTFIL. Matching records are written to the corresponding dataset(s). So one read and one sort produce many outputs.
| Scenario | Approach | Note |
|---|---|---|
| Same data, multiple copies | One OUTFIL with FNAMES=OUT1,OUT2,... | Identical stream to each DD |
| Different subsets (e.g. by department) | Multiple OUTFILs, each with INCLUDE= (or OMIT=) and different FNAMES= | One file per department or category |
| Different formats | Multiple OUTFILs, same or different filters, different BUILD= per OUTFIL | E.g. full record to one file, summary to another |
| Catch-all plus specific | OUTFILs with INCLUDE= for each category, last OUTFIL with SAVE | SAVE gets records not written by earlier OUTFILs |
Each OUTFIL statement defines one output stream. You can have as many OUTFILs as you need (within product limits). Each must specify FNAMES= so DFSORT knows which DD name(s) to write to. Example with three outputs:
1234SORT FIELDS=(1,10,CH,A) OUTFIL FNAMES=DEPT1,INCLUDE=(30,5,CH,EQ,C'DEPT1'),BUILD=(1,50) OUTFIL FNAMES=DEPT2,INCLUDE=(30,5,CH,EQ,C'DEPT2'),BUILD=(1,50) OUTFIL FNAMES=OTHER,SAVE,BUILD=(1,50)
The first OUTFIL writes only records where bytes 30–34 equal 'DEPT1' to the dataset allocated to DD name DEPT1. The second does the same for 'DEPT2' to DEPT2. The third has SAVE: it receives every record that was not written by the first or second OUTFIL (all records whose bytes 30–34 are neither DEPT1 nor DEPT2). All three outputs get a 50-byte built record. Your JCL must include //DEPT1 DD ..., //DEPT2 DD ..., and //OTHER DD ....
Most often each OUTFIL has a single DD name: FNAMES=OUT1. That OUTFIL's output goes only to the dataset allocated to OUT1. Use one FNAMES= per OUTFIL when each output is distinct (different filter or different BUILD).
You can list several DD names in one FNAMES=: FNAMES=OUT1,OUT2,OUT3. In that case, the same record stream—every record selected by this OUTFIL (and after any INCLUDE/OMIT and BUILD for this OUTFIL)—is written to all of those datasets. So OUT1, OUT2, and OUT3 get identical data. Use this when you need duplicate copies (e.g. one for production and one for archive, or one for region A and one for region B with the same content). The JCL must define all three DDs (//OUT1, //OUT2, //OUT3) with the appropriate DSN and DISP.
1OUTFIL FNAMES=MAIN,BACKUP,BUILD=(1,80)
Here, every record (no INCLUDE/OMIT) is built as 80 bytes and written to both MAIN and BACKUP. So you get two identical 80-byte files from one OUTFIL.
For every name you use in FNAMES=, you must have a corresponding DD statement in the same step. The DD specifies the dataset name (DSN=), disposition (DISP=), and optionally LRECL, RECFM, and SPACE. The record length written is determined by the OUTFIL (e.g. BUILD= length or full record length); the DD's LRECL should match. If you reference FNAMES=REPORT and do not have //REPORT DD ... in the JCL, the step will fail at allocation or when DFSORT tries to open the file.
DFSORT evaluates each record against the OUTFIL statements in the order they appear in SYSIN. For each record, the first OUTFIL whose condition (INCLUDE/OMIT, or no condition) is satisfied can write that record. So if OUTFIL1 has INCLUDE=(1,2,CH,EQ,C'01') and OUTFIL2 has INCLUDE=(1,2,CH,EQ,C'02'), a record with bytes 1–2 = '01' goes to OUTFIL1; a record with '02' goes to OUTFIL2. A record with '03' goes to neither unless you have a later OUTFIL with SAVE. The OUTFIL with SAVE should usually be last so it receives "everything else."
SAVE on an OUTFIL means: write to this OUTFIL any record that has not been written by any previous OUTFIL in this step. So you use one or more OUTFILs with INCLUDE (or OMIT) to send specific record types to specific files, and one final OUTFIL with SAVE to capture all remaining records. Without SAVE, records that do not match any OUTFIL's INCLUDE/OMIT are not written to any OUTFIL (they may still go to SORTOUT if you have one). With SAVE, you ensure no record is "dropped" from the OUTFIL side—every record goes to at least one OUTFIL (the first it matches, or the SAVE one).
Each OUTFIL can have a different BUILD= (or no BUILD, meaning full record). So one OUTFIL might write a 20-byte summary (BUILD=(1,10,30,10)) and another the full 80-byte record (BUILD=(1,80) or omit BUILD). That way you get a short extract in one file and the full detail in another from the same sort.
You can have both SORTOUT and multiple OUTFILs. By default, the main sorted stream goes to SORTOUT (after OUTREC if specified). OUTFILs add extra outputs. If you want the main output to also be filtered or reformatted by OUTFIL logic, you can use OUTFIL FNAMES=SORTOUT,... so that the primary output is controlled by that OUTFIL (e.g. INCLUDE= or BUILD=). Then the same record might go to SORTOUT and to other OUTFILs depending on your conditions.
Imagine one big pile of sorted cards and several boxes. Each box has a label (FNAMES=). The rule for Box 1 is "only cards that say DEPT1"; for Box 2 "only cards that say DEPT2"; for Box 3 "all the rest." You go through the pile once and put each card in the right box. You might also say "when you put a card in Box 1, only copy the first 50 letters onto a new card"—that's BUILD= for that box. So multiple outputs = one pass through the data, many boxes (files), each with its own rule and optional shorter copy.
1. How do you write to more than one output file from a single DFSORT step?
2. What does FNAMES=OUT1,OUT2 mean on a single OUTFIL?
3. What must you do in JCL when using OUTFIL FNAMES=REPORT1,REPORT2?
4. When would you use multiple OUTFILs instead of one SORTOUT?
5. Does the order of OUTFIL statements matter?