IFTHEN in DFSORT lets you apply conditional reformatting to records: different BUILD, OVERLAY, or FINDREP actions depending on whether a record meets specified conditions. You can use IFTHEN in both INREC and OUTREC. Each IFTHEN clause has a WHEN type—WHEN=INIT (apply to all), WHEN=(logical expression) (apply when condition is true), WHEN=NONE (apply when no previous WHEN matched), WHEN=ANY (apply when any previous WHEN matched), or WHEN=GROUP (group-level operations)—and an action such as BUILD= or OVERLAY=. Using IFTHEN in INREC is important when the conditionally reformatted record must be used for sorting or INCLUDE/OMIT; using it in OUTREC is for conditional formatting in the final output only. This page explains the five WHEN types, BUILD vs OVERLAY, and how to combine multiple clauses.
Sometimes you need different output layouts for different records: for example, header records get one format, detail records another, or records with a certain field value get an overlay (e.g. mask a field or insert a constant). Without IFTHEN, you would need a single BUILD that applies to every record. With IFTHEN, you say: "when the first 3 bytes equal 'ABC', build the record this way; when they don't, build it that way." So IFTHEN gives you conditional reformatting—different BUILD or OVERLAY depending on a condition. The same logic is available in INREC (before the sort) and OUTREC (after the sort). Use INREC when the result drives the sort or INCLUDE/OMIT; use OUTREC when you only need the conditional format in the final dataset.
Each IFTHEN clause is classified by its WHEN type. The order of processing and which records each applies to are different.
| WHEN type | Meaning | Typical use |
|---|---|---|
| WHEN=INIT | Apply BUILD/OVERLAY/FINDREP to all records; processed before other WHEN clauses | Base layout or common reformat for every record |
| WHEN=(logexp) | Apply only when the logical expression is true (e.g. field EQ value, PD GT 0) | Conditional layout for specific record types or values |
| WHEN=NONE | Apply to records that did not match any preceding WHEN=(logexp) | Else branch; default or fallback layout |
| WHEN=ANY | Apply to records that matched at least one preceding WHEN=(logexp) | Additional formatting for any record that matched a condition |
| WHEN=GROUP | Group-level operations (multiply fields, sequence numbers within groups); processed early | Control-break or group-based reformatting |
WHEN=INIT and WHEN=GROUP are processed before any WHEN=(logexp), WHEN=NONE, or WHEN=ANY. So you often use WHEN=INIT to build a base record (e.g. copy 1–80), then one or more WHEN=(logexp) to overlay or rebuild for specific conditions, and WHEN=NONE to handle records that did not match any condition. WHEN=ANY applies to records that already matched at least one WHEN=(logexp)—useful for adding something extra to any record that matched.
The logical expression in WHEN=(logexp) uses the same style of conditions as INCLUDE/OMIT: field position, length, format (CH, PD, ZD, BI), comparison operator (EQ, NE, LT, LE, GT, GE), and value (constant or another field). For example: WHEN=(1,3,CH,EQ,C'ABC') is true when the first 3 bytes are the character constant 'ABC'. WHEN=(10,4,ZD,GT,1000) is true when the 4-byte zoned decimal at position 10 is greater than 1000. When the expression is true, the BUILD or OVERLAY for that clause is applied to the record.
Inside an IFTHEN clause you specify what to do: BUILD= or OVERLAY= (or FINDREP when supported). BUILD= constructs a new record from the listed items (positions, constants, etc.)—it defines the full output record for that branch. OVERLAY= does not rebuild the whole record; it modifies specific positions. You give a position (and optionally length) and the new value (constant or field). So OVERLAY is useful when you want to change one or a few fields and leave the rest of the record unchanged. For example, replace an invalid date at position 72 with OVERLAY=(72:C'0001-01-01').
We want to reformat records so that if the first 3 bytes are 'ABC', the output is the first 20 bytes plus the constant 'FOUND_ABC'; otherwise the first 20 bytes plus 'NO_MATCH'. Doing this in INREC means the sort sees the reformatted record.
123SORT FIELDS=COPY INREC IFTHEN=(WHEN=(1,3,CH,EQ,C'ABC'),BUILD=(1,20,C'FOUND_ABC')), IFTHEN=(WHEN=NONE,BUILD=(1,20,C'NO_MATCH'))
The first IFTHEN applies when bytes 1–3 equal 'ABC'; the output is 20 bytes from input plus the 9-byte constant. The second IFTHEN with WHEN=NONE applies to all records that did not match the first—so they get 20 bytes plus 'NO_MATCH'. Every record is handled by exactly one of these two clauses.
Copy all records, but when the 4-byte zoned decimal at position 10 is greater than 1000, overlay position 1 with the constant 'OVER_1000'; when it is less than or equal to 1000, overlay with 'UNDER_1000'. Using OVERLAY we can keep the rest of the record and only change the first bytes.
1234SORT FIELDS=COPY OUTREC IFTHEN=(WHEN=INIT,BUILD=(1,80)), IFTHEN=(WHEN=(10,4,ZD,GT,1000),OVERLAY=(1:C'OVER_1000')), IFTHEN=(WHEN=(10,4,ZD,LE,1000),OVERLAY=(1:C'UNDER_1000'))
WHEN=INIT builds the base record (full 80 bytes from input). Then the two WHEN=(logexp) clauses overlay the first 9 bytes with the appropriate constant. So the output record is 80 bytes, with positions 1–9 replaced by the label. (If both conditions could apply, order matters; typically only one will apply per record.)
A common pattern is WHEN=INIT to set the base record for every record, then conditional OVERLAY to change specific fields when conditions hold. Example: copy 1–80 for everyone, then if bytes 30–34 are 'dept1', overlay position 45 with '***'; otherwise leave the record as built by INIT.
12OUTREC IFTHEN=(WHEN=INIT,BUILD=(1:1,80)), IFTHEN=(WHEN=(30,5,CH,EQ,C'dept1'),OVERLAY=(45:C'***'))
Here 1:1,80 places the input record at output starting at 1. Then the second clause overlays bytes 45–47 with '***' only when the condition is true. So you get one base layout and selective overlay without rewriting the whole BUILD for each case.
By default, often only the first matching WHEN=(logexp) (or WHEN=NONE) is applied. If you need multiple WHEN clauses to be evaluated and applied (e.g. overlay at one position when condition A holds, and at another position when condition B holds), you can use HIT=NEXT. This tells DFSORT to continue to the next IFTHEN after applying the current one, so more than one overlay can occur on the same record. For example, replace invalid date at 72 and also at 82 with '0001-01-01' when each field equals '9999-99-99'.
1234OUTREC IFTHEN=(WHEN=(72,10,CH,EQ,C'9999-99-99'), OVERLAY=(72:C'0001-01-01')),HIT=NEXT, IFTHEN=(WHEN=(82,10,CH,EQ,C'9999-99-99'), OVERLAY=(82:C'0001-01-01'))
The first IFTHEN overlays position 72 when the date there is the sentinel value; HIT=NEXT allows the second IFTHEN to run, which overlays position 82 when that date is the sentinel. So one record can get both overlays if both conditions are true.
WHEN=GROUP is used for group-level operations: for example, multiplying fields or generating sequence numbers within groups of records (e.g. by control field). It is processed early like WHEN=INIT. The exact syntax and use (e.g. with REFORMAT or group definitions) are in the IBM DFSORT manual. For most conditional reformatting by record type or field value, WHEN=INIT, WHEN=(logexp), and WHEN=NONE are sufficient.
Imagine you have a stack of cards: some have "ABC" at the top, some don't. IFTHEN is like a rule that says: "If the card says ABC, write 'FOUND_ABC' on it; if it doesn't say ABC, write 'NO_MATCH'." So the computer looks at each card, checks the condition, and then does the right action. WHEN=INIT is like doing something to every card first (e.g. copy it). Then the other rules only change some cards. That way different cards get different treatment without writing a separate program for each kind of card.
1. When is WHEN=INIT processed relative to other IFTHEN clauses?
2. What does WHEN=NONE do?
3. Why use IFTHEN in INREC instead of OUTREC?
4. What is OVERLAY in an IFTHEN clause used for?
5. What does HIT=NEXT do when used with IFTHEN?