In a JOINKEYS join, a record is matched when the other file has at least one record with the same join key. Records that have no matching key in the other file are unmatched (unpaired). By default, DFSORT keeps only matched pairs (inner join) and drops unmatched records. To keep unmatched records, you use JOIN UNPAIRED: JOIN UNPAIRED,F1 keeps all records from the first file (left outer join—unmatched F1 get blank F2); JOIN UNPAIRED,F2 keeps all from the second file (right outer—unmatched F2 get blank F1); JOIN UNPAIRED,F1,F2 keeps all from both (full outer). This page explains how unmatched records are handled, how the output is filled when one side is missing, and how to identify or split out unpaired rows for reporting or reconciliation.
If you do not code JOIN UNPAIRED, only records that have a matching key in both files are written. An F1 record with no F2 match is dropped. An F2 record with no F1 match is dropped. So the output contains only paired rows. That is the inner join and is the default.
JOIN UNPAIRED tells DFSORT to include unpaired records in the output. You specify which file(s) to preserve:
| Join type | Unpaired records | What to code |
|---|---|---|
| Inner (default) | Dropped | Do not code JOIN UNPAIRED |
| Left outer | All F1 kept; F2 blank when no match | JOIN UNPAIRED,F1 |
| Right outer | All F2 kept; F1 blank when no match | JOIN UNPAIRED,F2 |
| Full outer | All F1 and F2; other side blank when no match | JOIN UNPAIRED,F1,F2 |
REFORMAT defines the output layout as a sequence of F1: and F2: segments. For an unpaired F1 record, the F1 segment contains the actual F1 data; the F2 segment(s) are filled with blanks (for character data) or low values (e.g. zeros for numeric fields). For an unpaired F2 record, the F2 segment has the actual data and the F1 segment(s) are blank/low. So every output record has the same length and layout; you can tell unpaired rows by testing whether the "other" file’s portion is blank or zero.
12345JOINKEYS F1=CUSTOMER,FIELDS=(1,8,CH,A) JOINKEYS F2=ORDERS,FIELDS=(15,8,CH,A) REFORMAT FIELDS=(F1:1,80,F2:1,60) JOIN UNPAIRED,F1 SORT FIELDS=COPY
Every customer (F1) appears. Customers with orders get 80 bytes of customer data plus 60 bytes of order data (one row per order for one-to-many). Customers with no orders get one row each: 80 bytes of customer data and 60 bytes of blanks in the F2 area. Downstream you can select "F2 all blank" to list customers with no orders.
To isolate unpaired rows (e.g. for a report or separate file), use a follow-on step. For a left join, rows where the F2 portion is all blanks (or all zeros if numeric) are F1-only. You can use DFSORT INCLUDE/OMIT on that portion, or a COBOL/Assembler program that tests the F2 segment. For a full outer join, you have both: F1-only (F2 blank) and F2-only (F1 blank). A common pattern is to run the join with JOIN UNPAIRED, then OUTFIL with INCLUDE/OMIT or SPLIT to write matched vs unmatched to different datasets based on a test of the blank/low portion.
JOIN UNPAIRED must appear after both JOINKEYS and REFORMAT. Typical order: JOINKEYS F1=..., JOINKEYS F2=..., REFORMAT FIELDS=..., JOIN UNPAIRED,F1 (or F2 or F1,F2), SORT FIELDS=COPY or SORT FIELDS=.
You have a list of kids and a list of toys. Matching means same name. If you only keep pairs (kid + toy when both have that name), that’s inner—kids with no toy and toys with no kid are thrown away. If you keep every kid and add toy info when there is a toy (otherwise leave the toy part blank), that’s left join. If you keep every toy and add kid info when there is a kid (otherwise blank), that’s right join. If you keep every kid and every toy, with the other side blank when there’s no match, that’s full outer. Handling unmatched means deciding which of these you want and then spotting the blank parts later.
1. What does JOIN UNPAIRED,F1 do?
2. How can you tell in the output which rows were unmatched (e.g. F1 with no F2)?
3. You want all records from both files: those that match (with both sides), those only in F1 (F2 blank), and those only in F2 (F1 blank). What do you code?
4. For an unpaired F2 record (key in F2 but not in F1), what appears in the F1 portion of the output?
5. Why would you want to keep unmatched records?