The REFORMAT statement defines exactly how the joined output record is built from the two JOINKEYS files. You can specify multiple segments from each file, in any order: F1:position,length and F2:position,length. The output record is the concatenation of all segments in the order you list them, so the total length is the sum of every length. You can omit the join key, include it once, or include it from both files; you can pick non-contiguous ranges from either file. This page is a deep dive on REFORMAT: segment order, length calculation, how unpaired records are filled, and how to design the layout for downstream use.
Each item in REFORMAT FIELDS= is either F1:position,length or F2:position,length. Position is the starting byte in that file’s record (1-based). Length is how many bytes to copy. So F1:5,10 means bytes 5–14 from the first file; F2:1,20 means bytes 1–20 from the second file. The two files can have different record lengths; you are only specifying which ranges to pull and in what order. The output record has no "gaps"—each segment is placed immediately after the previous one.
You can list as many F1: and F2: items as you need, in any order. For example:
1REFORMAT FIELDS=(F1:1,10,F2:11,60,F1:11,30)
Output: first 10 bytes of F1 (e.g. key), then 60 bytes from F2 starting at position 11 (bytes 11–70 of F2), then 30 bytes from F1 starting at position 11 (bytes 11–40 of F1). Total length = 10 + 60 + 30 = 100 bytes. So you can reorder fields: put the key first, then part of F2, then more of F1. The order in the list is the order in the output.
| Item | Meaning |
|---|---|
| F1:1,80 | Bytes 1–80 from the first file (full record if length 80). |
| F2:11,70 | Bytes 11–80 from the second file (70 bytes); skips bytes 1–10 of F2. |
| F1:1,10,F2:1,10 | Key from F1 then key from F2 (key duplicated in output). |
| F2:1,20,F1:1,80 | First 20 bytes of F2, then full 80 bytes of F1 (order is your choice). |
The joined record length is always the sum of the length value in every F1: and F2: item. Position only says where to read from in each file; it does not change the output length. So plan your downstream record length (e.g. SORTOUT LRECL, copybook, or program) to match this sum. If you add or remove a segment, recalculate the total.
The join key is used by JOINKEYS for matching; it does not have to appear in REFORMAT at all, or it can appear once (from F1 or F2) or twice (from both). If the key is at 1–10 in both files and you want it once at the start of the output, use F1:1,10 (or F2:1,10). If you want key plus other F1 fields then F2 fields, you might use F1:1,80 (key plus rest of F1) and F2:11,70 (skip the key in F2 to avoid duplicate). It is up to you; REFORMAT does not enforce uniqueness of the key in the output.
You can skip bytes in either file by choosing position and length. For example F1:1,20 and F1:41,40 takes bytes 1–20 and 41–80 from F1 and omits bytes 21–40. So you can drop fields (e.g. a large filler) or reorder by listing non-contiguous segments. There is no requirement that segments be contiguous within one file.
When you use JOIN UNPAIRED, unpaired F1 records are written with the F1 segments containing real data and the F2 segments filled with blanks (character) or low values (e.g. zeros for numeric). Unpaired F2 records have F2 segments with real data and F1 segments blank/low. So every output record has the same length and layout; the "missing" side is blank/low so downstream can detect unpaired rows by testing those bytes.
Design REFORMAT so that the output layout matches what the next step expects: record length, field positions, and (if applicable) which bytes indicate unpaired (blank/low). If a program or another SORT step expects the key in a specific position, put the key segment there. If you need to flag unpaired rows, ensure the F1 or F2 "fill" area is at a fixed position and length so you can INCLUDE/OMIT or test it easily.
12345JOINKEYS F1=MASTER,FIELDS=(1,8,CH,A) JOINKEYS F2=DETAIL,FIELDS=(1,8,CH,A) REFORMAT FIELDS=(F1:1,80,F2:9,72) JOIN UNPAIRED,F1 SORT FIELDS=COPY
Join key is bytes 1–8 in both files. Output: full 80 bytes of F1 (including key at 1–8), then bytes 9–80 of F2 (72 bytes—F2 data after the key, so the key is not duplicated). Total 80 + 72 = 152 bytes. Unpaired F1 rows have bytes 81–152 blank/low.
REFORMAT is only for JOINKEYS: it builds the joined record from two files. INREC and OUTREC reformat a single record stream (one input). So in a join step you do not use INREC/OUTREC to define the join layout; you use REFORMAT. After the join, if you needed to further reformat the joined stream, you could use OUTREC in a subsequent SORT step that reads the join output.
You have two lists (F1 and F2). When two lines match, you make one new line. REFORMAT is the rule for that new line: "Take this chunk from the first list and that chunk from the second list, and stick them together in this order." You can take several chunks from the first list and several from the second, in any order you want. The new line is exactly as long as all those chunks added up. If one list has no match, we still write a line but fill the "other list’s" part with blanks so you can see it’s missing.
1. REFORMAT FIELDS=(F1:1,20,F2:5,10,F1:21,30). What is the output record length?
2. In REFORMAT, do the positions in F1: and F2: refer to the same output buffer?
3. For an unpaired F1 record, what goes into the F2 segments in the REFORMAT output?
4. Can you include the join key in the output more than once?
5. What is the main difference between REFORMAT and OUTREC in a join step?