Related
I have the following control cards that I can't understand how to read. Could someone help me traduce what this part of a JOB is performing?
OUTFIL FNAMES=(XSCB),BLKCCT1,INCLUDE=(67,7,CH,EQ,
C'XSCB ',OR,69,7,CH,EQ,
C'XSCB '),
HEADER2=(22:C'XSCB MVS USERID SYSTEM USAGE REPORT',/,
01:C'GENERATED ON ',&DATE=(MD4/),70:C'PAGE',&PAGE,/,
01:C' AT ',&TIME,/,X,/,
01:C'JULIAN',/,
01:C'DATE TIME SYSTEM JOB MESSAGE',/,
01:C'-------- -------- ------ -------- ---------------->'),
TRAILER1=(X,/,01:C'RECORDS FOUND =',COUNT,/,34:C'END OF REPORT'),
OUTREC=(20,07,ZD,EDIT=(TTTT.TTT),X, * JULIAN DATE
28,08,X, * TIME
11,06,X, * SYSTEM
40,08,X, * JOB OR REF
59,07,CHANGE=(50,C'IEF125I',C'LOGGED ON ', * MESSAGE
C'IEF126I',C'LOGGED OFF'),
NOMATCH=(79,50),
132:X)
I understand that it searches the ID 'XSCB' in the position 67 or 69. But once it finds it, I cannot interpret what it does next.
Those are SORT control cards. If you look at the SYSOUT for the step, and pay attention to the messages, you will be able to tell if it is DFSORT (messages prefixed by ICE) or SyncSORT (messages prefixed by WER).
Your step may be EXEC PGM=SORT or ICEMAN or something else, depends on your site.
The control cards are producing a report. You have at least one line missing from your control cards (OPTION COPY, or SORT FIELDS=COPY or a different SORT or MERGE statement). There could be any number of missing cards, and you possibly have another output from the step. Otherwise the OUTFIL INCLUDE= could perhaps be a plain INCLUDE COND=.
What does what you have shown actually do?
OUTFIL defines final processing for a particular output data set. With no name, it would be for the SORTOUT DD in your JCL.
With FNAMES=(XSCB) it is for a DD named XSCB in your JCL. For a single name specified in FNAMES, the brackets are redundant.
BLKCTT1 says "put a blank in column one to not get a page-eject from TRAILER1 output".
The INCLUDE= is as you suspect. Testing two different starting positions for the same value. If either test is true, the current record will be included in the OUTFIL group.
HEADER2 defines what appears at the top of each page.
The 01: is a column-number, and is redundant, as each line by default starts are column one.
HEADER2 can create multiple lines (as can any HEADERn or TRAILERn and BUILD (or OUTREC, but don't use it for new) on OUTFIL), each separated by "/". &DATE, &TIME and &PAGE are special, containing the obvious. &DATE can be formatted in various ways, MD4/ is MM, DD, YYYY separated by slashes.
The X is a blank, on a line of its own. You could equally see .../,/... or n/ to create n multiple blank lines.
The constants should be obvious.
TRAILER1 defines what is printed at the end of the report.
COUNT is the number of records in the OUTFIL group, here used with no formatting, but it can be formatted.
The 34: column-number means the items following will start from column 34.
The OUTREC is better spelled as BUILD. OUTREC exists elsewhere. BUILD has been around for more than 10 years, so no need to use OUTREC on OUTFIL in new code (maybe this is old anyway).
What the BUILD would do is format the current input record into what is desired for an output line on the report.
The numbers in pairs are start-position and length of fields. Where no field-type is defined, they are (treated as) character fields.
You have one field-type, ZD, which is zoned-decimal. Its length is seven, and an EDIT mask is used, four digits, full-stop (decimal-point) and then three digits.
The Xs as previously are blanks, used as separators on the report. The content of each field is described in a comment. A comment is any text after the end of a control card. A control card ends at the blank after the statement is complete, or where a there is a blank after a possible continuation (a comma or a colon are possible continuations).
132:X puts a blank in column 132, and pads any intervening columns from the last field or constant with blanks.
That leaves the CHANGE=.
CHANGE= is a very useful test-and-replace.
79,50,CHANGE=(50,C'IEF125I',C'LOGGED ON ', * MESSAGE
C'IEF126I',C'LOGGED OFF'),
NOMATCH=(79,50)
This says "at the current column of the record being created, consider the content of the input from position 79 for a length of 50. The output length will be 50. If IEF125I, then use the constant LOGGED ON, if IEF126I use LOGGED OFF, and else (NOMATCH) use whatever is at position 79 for a length of 50 from the input.
Basically, the report is using the system log, or an extract from it, to report activity related to the Userid/Logon XSCB.
I want to write a sort JCL with requirement where I want to sort on variable record length file
Input file:
Mark aaaaaaa
Amy bbbbbb
Paula ccccccccccc
Sort on the length of field before spaces on ascending order. That is sorting on length of first col/word Mark,Amy etc.. On basis of their length.
And second one is like performing sort on field after spaces on descending order but if any vowels in field should always be first and then rest of data.
Coming on second part ,here it's like the fields after spaces or aaaaa, bbbbb and ccccc we need to sort it in descending order (alphabetically) ,but then we also need to check if the field is vovel ,if any vovel then that field will be always as top, so the expected output will be like:
Considering above input file output file will be:
Mark aaaaaaaa
Paula cccccc
Amy bbbbbb
Now here vovel as in first record which contains aaaa in it is at top and rest data is sorted in descending order. I want to achieve this.
What you are asking is not at all a simple thing :-)
Whilst DFSORT has much intrinsic functionality, finding the length of a sequence of non-space characters is not available.
So you have to roll-your-own.
Although the task is also possible with fixed-length records (different technique) it is easier with variable-length records.
Because the fields are variable-length as well, you'll need PARSE to separate the fields. For variable-length or variably-located fields, PARSE is usually the answer.
PARSE creates fixed-length parsed fields, so you have to know the maximum lengths of your text. In this example 30 is chosen for each.
The solution will develop piece by piece, because you will need to be secure in your understanding of it. The pieces are presented as "stand alone" code which you can run and see what happens:
OPTION COPY
INREC IFTHEN=(WHEN=INIT,
PARSE=(%01=(ENDBEFR=C' ',
FIXLEN=30),
%02=(FIXLEN=30))),
IFTHEN=(WHEN=INIT,
BUILD=(1,4,%01,%02))
If you run that, you will get this output:
MARK AAAAAAA
AMY BBBBBB
PAULA CCCCCCCCCCC
INREC runs before a SORT, so to make any changes to the data before a SORT, you use INREC. OUTREC runs after SORT, and OUTFIL after OUTREC.
For now, the BUILD is just to show that the PARSEd fields contain the output you want (don't worry about the case, if you used mixed-case it will be like that).
WHEN=INIT means "do this for each record, before the following IFTHEN statements (if any)". You can use multiple WHEN=INIT, and you have to use multiple IFTHEN of some type to transform data in multiple stages.
The 1,4 in the BUILD is for the Record Descriptor Word (RDW) which each variable-length record hase, and is always necessary when creating a variable-length current record in SORT, but we'll use it for another purpose here as well.
The next stage is to "extend" the records, because we need two fields to SORT on. For a variable-length record, you extend "at the front". In general:
BUILD=(1,4,extensionstuff,5)
This makes a new version of the current record, with first the RDW from the old current record, then "does some stuff" to create the extension, then copies from position 5 (the first data-byte on a variable-length record) to the end of the record.
Although the RDW is "copied", the value of the RDW at the time is irrelevant, as it will be calculated for the BUILD. It just must be an RDW to start with, you can't just put anything there except an actual RDW.
Another component that will be needed is to extend the records for the SORT key. We need the length of the first field, and we need a "flag" for whether or not to "sort early" for the second field containing a vowel. For the length it will be convenient to have a two-byte binary value. For now, we are just reserving bytes for the things:
OPTION COPY
INREC BUILD=(1,4,2X,2X,X,5)
The 2X is two blanks, the X is one blank, so a total of five blanks. It could have been written as 5X, and in the final code is best that way, but for now it is clearer. Run that and you will see your records prefixed by five blanks.
There are two tasks. The length of the first field, and whether the second field contains a vowel.
The key to the first task is to replace blanks from the PARSEd field with "nothing". This will cause the record to be shortened by one for each blank replaced. Saving the length of the original current record, and calculating with the length of the current record and the fixed-length (30) reveals the length of the data.
The key to the second task applies a similar technique. This time, change the second PARSEd field such that a, e, i, o, u are replaced by "nothing". Then if the length is the same as the original, there were no vowels.
The FINDREP will look something like this:
IFTHEN=(WHEN=INIT,
FINDREP=(IN=C' ',
OUT=C'',
STARTPOS=n1,
ENDPOS=n2)),
You'll need a variant for the vowels:
IFTHEN=(WHEN=INIT,
FINDREP=(IN=(C'A',C'E',C'I',C'O',C'U'),
OUT=C'',
STARTPOS=n1,
ENDPOS=n2)),
To run:
OPTION COPY
INREC IFTHEN=(WHEN=INIT,
PARSE=(%01=(ENDBEFR=C' ',
FIXLEN=30),
%02=(FIXLEN=30))),
IFTHEN=(WHEN=INIT,
BUILD=(1,4,2X,X,%02)),
IFTHEN=(WHEN=INIT,
OVERLAY=(5:1,2)),
IFTHEN=(WHEN=INIT,
FINDREP=(IN=(C'A',
C'E',
C'I',
C'O',
C'U'),
OUT=C'',
STARTPOS=8,
ENDPOS=38)),
IFTHEN=(WHEN=(1,4,BI,EQ,5,2,BI),
OVERLAY=(7:C'N'))
If you run that, you will see the flag (third data-position) is now space (for a vowel present) or "N". Don't worry that all the "A"s have disappeared, they are still tucked away in %02.
OVERLAY can make changes to the current record without creating a new, replacement record (which is what BUILD does). You'll see OVERLAY used below to get the new record-length after the a new current record-length has been created (the BUILD would get the original record-length from the RDW).
A similar process for the other task.
I've included some additional test-data and made further assumptions about your SORT order. Here's full, annotated (the comments can remain, they do not affect the processing), code:
* PARSE CURRENT INPUT TO GET TWO FIELDS, HELD SEPARATELY FROM THE RECORD.
*
INREC IFTHEN=(WHEN=INIT,
PARSE=(%01=(ENDBEFR=C' ',
FIXLEN=30),
%02=(FIXLEN=30))),
* MAKE A NEW CURRENT RECORD, RDW FROM EXISTING RECORD, THREE EXTENSIONS, AND
* A COPY OF THE FIRST PARSED FIELD.
*
IFTHEN=(WHEN=INIT,
BUILD=(1,4,
2X,
2X,
X,
%01)),
* STORE THE LENGTH OF THE NEW CURRENT RECORD ON THE CURRENT RECORD.
*
IFTHEN=(WHEN=INIT,
OVERLAY=(5:
1,2)),
* REPLACE BLANKS WITH "NOTHING" WITHIN THE COPY OF THE PARSED FIELD. THIS WILL
* AUTOMATICALLY ADJUST THE RDW ON THE CURRENT RECORD.
*
IFTHEN=(WHEN=INIT,
FINDREP=(IN=C' ',
OUT=C'',
STARTPOS=10,
ENDPOS=40)),
* CALCULATE THE LENGTH OF THE NON-BLANKS IN THE FIELD, BY SUBTRACTING PREVIOUS
* STORED RECORD-LENGTH FROM CURRENT RECORD-LENGTH (FIRST TWO BYTES, BINARY, OF
* RDW) AND ADDING 30 (LENGTH OF PARSED FIELD).
*
IFTHEN=(WHEN=INIT,
OVERLAY=(5:
1,2,BI,
SUB,
5,2,BI,
ADD,
+30,
TO=BI,
LENGTH=2)),
* MAKE A NEW CURRENT RECORD, COPYING RDW AND THE VALUE CALCULATED ABOVE, BLANKS
* (COULD BE COPIED) AND THEN THE SECOND PARSED FIELD.
*
IFTHEN=(WHEN=INIT,
BUILD=(1,4,
5,2,
2X,
X,
%02)),
* AGAIN SAVE THE LENGTH OF THE NEW CURRENT RECORD.
*
IFTHEN=(WHEN=INIT,
OVERLAY=(7:
1,2)),
* CHANGE ALL VOWELS TO "NOTHING". THIS WILL AUTOMATICALLY ADJUST THE RDW. FOR
* MIXED-CASE JUST EXTEND THE IN TO INCLUDE LOWER-CASE VOWELS AS WELL.
*
IFTHEN=(WHEN=INIT,
FINDREP=(IN=(C'A',
C'E',
C'I',
C'O',
C'U'),
OUT=C'',
STARTPOS=10,
ENDPOS=40)),
* CALCULATE NUMBER OF VOWELS.
*
IFTHEN=(WHEN=INIT,
OVERLAY=(7:
7,2,BI,
SUB,
1,2,BI,
TO=BI,
LENGTH=2)),
* MAKE A NEW CURRENT RECORD TO BE SORTED, WITH BOTH PARSED FIELDS.
*
IFTHEN=(WHEN=INIT,
BUILD=(1,4,
5,2,
7,2,
9,1,
%01,
%02)),
* SET THE FLAG TO "OUTSORT" THOSE RECORDS WITH A VOWEL IN THE SECOND FIELD.
*
IFTHEN=(WHEN=(7,2,BI,EQ,0),
OVERLAY=(9:
C'N'))
* SORT ON "OUTSORT FLAG", LENGTH OF NAME (DESCENDING), NAME, 2ND FIELD.
SORT FIELDS=(9,1,CH,A,
5,2,CH,D,
10,30,CH,A,
40,30,CH,A)
* FIELDS NEEDED TO BE IN FIXED POSITION FOR SORT, AND EXTENSION FIELDS NO
* LONGER NEEDED. ALSO REMOVE BLANKS FROM THE TWO FIELDS, KEEPING A SEPARATOR
* BETWEEN THEM. THIS COULD INSTEAD BE DONE ON THE OUTFIL.
*
OUTREC BUILD=(1,4,
10,60,
SQZ=(SHIFT=LEFT,
MID=C' '))
* CURRENTLY THE VARIABLE-LENGTH RECORDS ARE ALL THE SAME LENGTH (69 BYTES) SO
* REMOVE TRAILING BLANKS.
*
OUTFIL VLTRIM=C' '
Extensive test-data:
MARK AAAAAAA
AMY BBBBBB
PAULA CCCCCCCCCCC
PAULA BDDDDDDDDDD
IK JJJJJJJJJJO
You can also see how the code works by "removing a line at a time" from the end of the code, so you can see how the transformation reaches that point, or by running the code increasing a line at a time from the start of the code.
It is important that you, and your colleagues, understand the code.
There are some opportunities for some rationalisation. If you can work those out, it means you understand the code. Probably.
We have three different file one is like that
File A
000001000
000002000
000003000
000004000
File B (After Summing of all Records in file A)
000010000
File C
Total : - 10000
I have to compare the value in the File C and File B and if the value matches successfully I have to set the desired Return Code RC.
The starting position of the word "Total" is five.
I also find the solution of the problem using the JOINKEY.
The code is given below.
//STEP1 EXEC PGM=SORT,PARM=’NULLOUT=RC4′
//SORTJNF1 DD DSN=FILEB
//SORTJNF2 DD DSN=FILEC
//SORTOUT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//SYSIN DD *
JOINKEYS FILE=F1,FIELDS=(1,9,A)
JOINKEYS FILE=F2,FIELDS=(5,9,a)
REFORMAT FIELDS=(F1:1,80)
OPTION COPY
/*
When the Match is success full it will return the RC=0
And
When Match is not success full it will return the RC=4 as it is supplied using the PARM.
Basically it search for the record in the output file (sortout) if Match successful the jcl sort utility will copy the record from fileB into the Output file(in spool) and if the unsuccessful match then the output file is empty and the with the help of PARM=’NULLOUT=RC4′ it return the RC=4.
Why you wouldn't use JOINKEYS?
A professional would know not to use JOINKEYS for this task or would recognise specific advice against using it.
For everyone else, here's why not.
JOINKEYS consists of three "Tasks", the Main Task and two Sub-Tasks (one for each input dataset). This means JOINKEYS can use up to three times the memory of a plain SORT/MERGE/COPY. This means a JOINKEYS step can be more difficult to "select" and can keep other JOBs from being selected. It also means a JOINKEYS step is going to be slower than an if an equivalent solution is possible not using JOINKEYS (this can depend on the exact solution, but is true for anything trivial).
More memory, more CPU, more elapsed time, more impact on other JOBs.
Only use JOINKEYS where necessary. Necessary does not mean "so I can type/copy-paste less code", it means when a good solution requires the use of JOINKEYS.
If a solution does not require JOINKEYS, then don't use JOINKEYS. Someone pays for the extra resources and impacts. A professional avoids such costs.
Of course, such advice is free, and you get what you pay for at times. However, I am the DFSORT Moderator at www.ibmmainframes.com, taking over that task from Frank Yaeger of IBM, the inventor of the modern DFSORT.
Plus in the sample code given by https://stackoverflow.com/users/5433120/sharad-singhal, the JOINKEYS won't even work with the data that they themselves showed in the question, as the field-types are different (one left-zero filled, the other leading-zero truncated, right-space-padded).
You can of course normalise the second key, using a JNF2CNTL DD and some code (the code needed is included here).
But. Even. Though. It. Can. Be. Made. To. Work. JOINKEYS. Is. A. Bad. Solution. For. This. Task.
I hope this is clear for any future searchers.
I have to set the desired Return Code RC
This is impossible, except by coincidence. The only Condition Code/Return Code (CC/RC) available to you from DFSORT is zero, four and 16.
Perhaps that provides one of the CC/RC which you desired. If not, change your desire. Or do it the odd way around by using an IDCAMS step to "convert" the CC/RC you get from DFSORT to the CC/RC you so desperately want.
The only way you can get, with correct control cards, other than a zero RC is by having an empty output file (either SORTOUT or an OUTFIL dataset).
You want to SUM. SUM requires SORT or MERGE. You can also use OUTFIL reporting functions, REMOVECC and TOTAL to get sums, but by that time you don't have an opportunity to test that two totals are equal, or not.
Matching datasets is a good task for JOINKEYS.
You can also code the summation yourself.
Resource-wise and since you are probably a beginner, the best solution will be the MERGE.
You need two DD's in your JCL, SORTIN01 and SORTIN02, in place of SORTIN which you would usually have for a SORT step. You will also need at least one output DD, which can be SORTOUT, but best as another, and this should be set to DUMMY or DSN=NULLFILE.
You need to arrange that all the value records get a "key" which is equal, so that they can be SUMmed, and your Total record should get a different value.
//MATCHTOT EXEC PGM=SORT
//SYMNAMES DD *
* IN- is the input records with values (and the summed value later)
* EXT- are temporary extensions made to the record for processing
* TOT- is the total record
* IND- is an indicator determining wheter value or total record
IN-RECORD,*,80,CH
EXT-IN-IND,*,1,CH
EXT-TOT-TOTAL-VALUE,*,9,zd
POSITION,IN-RECORD
IN-VALUE,=,9,ZD
IN-SUM-VALUE,=,=,=
POSITION,IN-RECORD
SKIP,5
TOT-TOTAL-NAME,*,5,CH
SKIP,5
TOT-TOTAL-VALUE,*,9,CH
* Constants
TOTAL-TEXT,C'Total'
IND-TOT-TOTAL,C'0'
IND-IN-VALUE,C'5'
CLOBBER-FIRST-PART,C'000000000'
//SYMNOUT DD SYSOUT=*
//CHECK DD DUMMY
//SYSOUT DD SYSOUT=*
//SORTOUT DD SYSOUT=*
//FILEB DD SYSOUT=*
//SYSIN DD *
INREC IFTHEN=(WHEN=(TOT-TOTAL-NAME,
EQ,
TOTAL-TEXT),
OVERLAY=(EXT-IN-IND:
IND-TOT-TOTAL,
IN-VALUE:
CLOBBER-FIRST-PART)),
IFTHEN=(WHEN=NONE,
OVERLAY=(EXT-IN-IND:
IND-IN-VALUE))
MERGE FIELDS=(EXT-IN-IND,A)
SUM FIELDS=(IN-VALUE)
OUTREC IFTHEN=(WHEN=GROUP,
BEGIN=(EXT-IN-IND,
EQ,
IND-TOT-TOTAL),
PUSH=(EXT-TOT-TOTAL-VALUE:
TOT-TOTAL-VALUE)),
IFTHEN=(WHEN=INIT,
OVERLAY=(EXT-TOT-TOTAL-VALUE:
EXT-TOT-TOTAL-VALUE,UFF,
TO=ZD,
LENGTH=9))
OUTFIL FNAMES=CHECK,
INCLUDE=(EXT-IN-IND,
EQ,
IND-IN-VALUE,
AND,
IN-SUM-VALUE,
EQ,
EXT-TOT-TOTAL-VALUE),
NULLOFL=RC4
OUTFIL FNAMES=FILEB,
INCLUDE=(EXT-IN-IND,CH,EQ,IND-IN-VALUE),
BUILD=(IN-RECORD)
//SORTIN01 DD *
000001000
000002000
000003000
000004000
//SORTIN02 DD *
Total : - 20000
This uses DFSORT symbols/SYMNAMES. These are defined on the SYMNAMES DD (best as a PDSE (or PDS) member, fixed-length 80-byte records.
The SYMNOUT DD statement lists the source symbols, and the normalised symbols which will by used by DFSORT to translate the control cards.
In INREC, the key for the merge is established and in the case of the Total record, the input positions (no longer required) that match the value on the value records are set to zero. Any data from an input file which is not needed for output can be happily destroyed (if it is not written, it is not written, so its content is irrelevant and can be amended if convenient to do so).
The MERGE then uses the key just established. This is just a trick to allow SUM to be used. All the value records (key five) will be SUMmed to an actual value, the total record will be left as it is (since its key is unique).
In OUTREC, the total from the Total record will be PUSHed to the next record (the SUMmed values) using WHEN=GROUP. The Unsigned Free Format data of the Total record will be converted to a Zoned Decimal value.
There are then two OUTFIL statements.
The first looks at the SUMmed record and compares the value to the value PUSHed from the Total record. If they are equal, a record is written to the OUTFIL (which is DUMMY in the JCL). The RC4 will not be set. If the values are different, no record will be written and the RC4 will be set.
The second OUTFIL is to create your FILEB, which is not itself needed as a file. If you don't need FILEB for anything else, you can remove this OUTFIL.
I have left the SORTOUT DD in the JCL so you can see what happens to the records. You can remove this once you are happy you know what is going on.
The only other RC you can get is 16. Avoid this as 16 is also produced for Control Card or run-time errors.
So I have a set of data such as this:
mxyzd1 0000015000
mxyzd2 0000016000
xyzmd5823 0000017000
I need to use dfsort to get this data:
123xyzd1 0000015000
123xyzd2 0000016000
xyz123d5820000017000
So what I mean is: replace all character 'm' by '123' without overwriting the second column, so truncate data before you get to the second column (which starts at pos 11).
So far I've been able to replace the data but can't prevent all of my data of getting shifted, this is my code so far:
SYSIN DATA *
SORT FIELDS=(1,1,CH,A)
OUTREC FINDREP=(IN=C'm',OUT=C'123',STARTPOS=1,ENDPOS=10,
MAXLEN=20,OVERRUN=TRUNC,SHIFT=YES)
DATAEND
*
The problem you are facing is that all data on a record will be shifted to the right if the FINDREP change increases the length, and to the left if the FINDREP change decreases the length. Any change in the length of the changed data affects the entire record. You have discovered this yourself.
To put that another way, FINDREP does not know about fields (columns are best termed something like that) it only knows about records, even when it is looking only at a portion of the record, changes in length reflect on the rest of the record.
There is no way to write just a FINDREP to avoid this.
OPTION COPY
INREC IFTHEN=(WHEN=INIT,
OVERLAY=(21:1,10)),
IFTHEN=(WHEN=INIT,
FINDREP=(IN=C'm',
OUT=C'123',
STARTPOS=21)),
IFTHEN=(WHEN=INIT,
BUILD=(21,10,
11,10))
This will put the data from 1,10 into a temporary extension to the record. It will do the FINDREP on the temporary extension only. Then it will take the first 10 bytes of the extension and put them into position one for a length of 10.
Just make one small change in your sort card - SHIFT=NO
SORT:
JOINKEYS FILES=F1,FIELDS=(5,4,A,10,20,A)
JOINKEYS FILES=F2,FIELDS=(1,4,A,6,20,A)
REFORMAT FIELDS=(F1:10,20,9,1,5,4,30,1,31,10,F2:27,10)
JOIN UNPAIRED,F1
INREC BUILD=(1,36,C',',37,10,C',',27,10,SFF,SUB,37,10,SFF,
EDIT=(TTTTTT))
OUTPUT IS: *2nd row 4th column is spaces as unpaired from 2nd file, needs to be 0s automatically.
22680372 ,5102, 1, 1,000000
22222222 ,5105, 2, ,000002
OUTPUT shud be: *2nd row 4th column is 0 or 0000s as unpaired from 2nd file, needs to be 0s automatically.
22680372 ,5102, 1, 1,000000
22222222 ,5105, 2, 0,000002
You need a condition, which means IFTHEN. You can't have IFTHEN and BUILD on the same INREC, but you can have multiple IFTHENs and BUILD can be part of an IFTHEN.
IFTHEN=(WHEN=INIT indicates something which should be done for every record (unconditional).
IFTHEN=(WHEN=(logical-expression will only be actioned if the condition is true.
Every BUILD statement makes a complete new intermediate record (intermediate between input and output). OVERLAY only affects the data at the position specified (assuming no extension of the record).
Your condition will be that the 46th byte of the record is space. You have already used SFF (did you try the other suggestions, especially FS?), so there is no need to make the value zero before the BUILD.
JOINKEYS FILES=F1,FIELDS=(5,4,A,10,20,A)
JOINKEYS FILES=F2,FIELDS=(1,4,A,6,20,A)
REFORMAT FIELDS=(F1:10,20,9,1,5,4,30,1,31,10,F2:27,10)
JOIN UNPAIRED,F1
INREC IFTHEN=(WHEN=INIT,
BUILD=(1,36,
C',',
37,10,
C',',
27,10,SFF,
SUB,
37,10,SFF,
EDIT=(TTTTTT))),
IFTHEN=(WHEN=(47,1,CH,EQ,C' '),
OVERLAY=(46:C'0'))
I don't format the statements like that just for fun, but to make them easier to understand and maintain.
OK, that solution was a little clunky. You can replace the INREC with this, which shows, for this type of data, an alternative to the EDIT:
INREC IFTHEN=(WHEN=INIT,
BUILD=(1,36,
C',',
37,10,FS,TO=FS,LENGTH=10,
C',',
27,10,FS,
SUB,
37,10,FS,
TO=FS,LENGTH=8))
This is much more natural, as the space gets turned into a zero with leading blanks with no conditions at all, and using references only to that field in its position on the REFORMAT record.