I would like informations to manipulate tables.
I encounter few problem with a piece of cobol code like below:
01 TABLE-1.
05 STRUCT-1 OCCURS 25 TIMES.
10 VALUE-1 PIC AAA.
10 VALUE-2 PIC 9(5)V999.
05 NUMBER-OF-OCCURS PIC 99.
How do you update values? (update a VALUE-2 when you know a VALUE-1)
How look up a value and add new one?
Thanks a lot!
How to look up a value/How to update a value
First you have to look up the record (row) that you want to update. This is typically done by searching the table for
a given key value. COBOL provides a couple of ways to do this. I recommend that you start by
reviewing the COBOL SEARCH
statement. If STRUCT-1 records are sorted, you could use SEARCH ALL, otherwise you must use SEARCH or just code
your own search loop. In order to use any of these techniques you will need to declare another variable somewhere
in your program to use as an index (offset) into the STRUCT-1 table. COBOL provides the INDEXED BY phrase on the
OCCURS clause to declare an index specific to the given table
(see OCCURS)
Once you have set the index into STRUCT-1 to point to the row to be updated you just MOVE the
value to the appropriate variables within that row, for example
MOVE 123.456 TO VALUE-2 (IDX-1)
where IDX-1 is the index referred to above. Note that you can use either an integer or
index variable
to specify the row number to be updated, you are not limited to using an INDEX type variable. However,
it is generally more efficient to use INDEX variables over other types of variables, particularily
when working with multi-dimensional tables where the program makes lots of references to the table.
How to add a new row
First recognize that STRUCT-1 contains exactly 25 rows. COBOL does not have a mechanism to dynamically
increase or decrease this number (I've heard this will possible in the next ISO COBOL standard - but don't
hold your breath waiting for it). Technically all 25
rows are available at any time. However a common convention is to 'grow' a table from being empty
to full sequentially, one row at a time. To use this convention you need to assign a variable to
keep track of the last used row number (don't forget to initialize this variable to zero at program startup).
In your example it looks like the variable NUMBER-OF-OCCURS does this job
(I didn't mention it but, you need this variable to bound the SEARCH discussed above).
To 'add' a row, just increment NUMBER-OF-OCCURS by 1. Be careful not to exceed the table size. Example
code might be:
IF NUMBER-OF-OCCURS < (LENGTH OF TABLE-1 / LENGTH OF STRUCT-1 (1))
ADD +1 TO NUMBER-OF-OCCURS
ELSE
table is full, preform some error/recovery routine
END-IF
The above code avoids the explicit use of the number of occurs in TABLE-1 which in turn can save
a number of maintenance problems when/if the number of OCCURS is ever changed.
See the NOTE at the bottom: There is a really big Woops here - did you catch it!
Now back to the search problem. The following code example illustrates how you might
proceed:
WORKING-STORAGE Declaration:
01 FOUND-IND PIC X(1).
88 FOUND-YES VALUE 'Y'.
88 FOUND-NO VALUE 'N'.
77 MAX-IDX USAGE IS INDEX.
01 TABLE-1.
05 STRUCT-1 OCCURS 25 TIMES INDEXED BY IDX-1.
10 VALUE-1 PIC AAA.
10 VALUE-2 PIC 9(5)V999.
05 NUMBER-OF-OCCURS PIC 99.
What was added:
FOUND-IND is used to indicate whether the row you are looking for has been found. The 88 levels give specific values to set/test
MAX-IDX is used to set an upper bound limit on the search. You could use NUMBER-OF-OCCURS in the upper bounds test but this would force a data type converson on every test which isn't very efficient
IDX-1 is used as the index (offset) into the STRUCT-1 table.
Personally, I would declare NUMBER-OF-OCCURS as PIC S9(4) BINARY but what you have will work.
Assuming that STRUCT-1 is not sorted and NUMBER-OF-OCCURS represents the current
number of active rows in STRUCT-1 this
is an example of how you might code the SEARCH when looking for the value 'ABC':
SET FOUND-NO TO TRUE
IF NUMBER-OF-OCCURS > ZERO
SET IDX-1 TO 1
SET MAX-IDX TO NUMBER-OF-OCCURS
SEARCH STRUCT-1
WHEN IDX-1 > MAX-IDX
CONTINUE
WHEN VALUE-1 (IDX-1) = 'ABC'
SET FOUND-YES TO TRUE
END-SEARCH
END-IF
IF FOUND-YES
row found, use IDX-1 to reference the row containing 'ABC'
ELSE
row not found, IDX-1 does not contain a valid index
END-IF
How it works:
Start by assuming the row is not in the table by setting FOUND-NO to true.
The first IF ensures that there is at least 1 active row in STRUCT-1 before beginning the search (it is an error to set an INDEX to zero - so you need to guard against that).
The SEARCH terminates when the first SEARCH WHEN clause is satisified. That is why the 'do nothing' verb CONTINUE can be used when we run out of rows to search. The other terminating condition (finding the value you are looking for) is the only place where FOUND-YES can be set.
When the SEARCH completes, test for success or failure then act accordingly.
Some exercises for you to research:
Why did I not have to code an AT END clause in the SEARCH statement?
Why did I not have to code a VARYING clause in the SEARCH statement?
Why did I code the WHERE clauses in the order that I did?
Hope this gets you started down the right path.
Edit
In response to your question in the comments: Could we use NUMBER-OF-OCCURS as index for the search. The
answer is yes, but you need to implement some different rules. When using NUMBER-OF-OCCURS
as an index you can no longer use it to keep track of how many rows currently contain
valid data. This means you need another mechanism to identify unused rows in STRUCT-1.
This might be accomplished by initializing un-used rows with a sentinal value (eg. LOW-VALUE) that you
will never actually want to put into the table. The SEARCH becomes:
SET FOUND-NO TO TRUE
MOVE 1 TO NUMBER-OF-OCCURS
SEARCH STRUCT-1 VARYING NUMBER-OF-OCCURS
WHEN VALUE-1 (NUMBER-OF-OCCURS) = 'ABC'
SET FOUND-YES TO TRUE
END-SEARCH
The above will search every row in STRUCT-1 in the event that the value you are searching for
(ie. ABC) is not in the table. As an optimization you can add a second WHEN clause to terminate the
search upon finding a sentinal value:
WHEN VALUE-1 (NUMBER-OF-OCCURS) = LOW-VALUE
CONTINUE
The above assumes LOW-VALUE was used to identify unused rows. You can also drop IDX-1 and MAX-IDX
from your working storage since this solution doesn't need them.
Using NUMBER-OF-OCCURS as an index also means you must change the way you search for an empty row
to insert a new value. The easiest way to do this is to search the table using the above
code for LOW-VALUE instead of 'ABC'. If FOUND-YES has been set at the end of the search, then
NUMBER-OF-OCCURS is the index of the first unused row. If FOUND-NO has been set, then the table is
already full.
The above code is a lot simpler than what I initially suggested. So why did I give you the more
complicated solution? The more complicated solution is more efficient because it makes many
fewer internal offset calculations and data type conversions when running through the table.
It also avoids doing an additional
SEARCH to find the next unused row. These efficiencies
may not be of concern in your application, but if the tables are large and accessed frequently you
should be aware of the performance aspect of searching tables and forced data type conversions (for
example the cost of converting a PIC 99 field into an index reference).
Note:
My original example to calculate whether the table was full using the LENGTH OF special register
would work in this example but has a really bad built in assumption! The LENGTH OF TABLE-1 includes
not only the STRUCT-1 table but the NUMBER-OF-OCCURS too. The length of NUMBER-OF-OCCURS is less than one
occurance of STRUCT-1 so it all works out ok due to truncation of the result into an integer value.
This is a very good example of code working correctly for the wrong reason! To make the proper calculation
you would have to adjust your working storage to something like:
01 TABLE-1.
05 STRUCT-TABLE.
10 STRUCT-1 OCCURS 25 TIMES.
20 VALUE-1 PIC AAA.
20 VALUE-2 PIC 9(5)V999.
05 NUMBER-OF-OCCURS PIC 99.
and the bounds calculation would become:
IF NUMBER-OF-OCCURS < (LENGTH OF STRUCT-TABLE / LENGTH OF STRUCT-1 (1))
ADD +1 TO NUMBER-OF-OCCURS
ELSE
table is full, preform some error/recovery routine
END-IF
Or you could just move NUMBER-OF-OCCURS out of the TABLE-1 record definition.
In order to populate and amend data in tables in working-storage section you need to use a subscript/index, which you can define in the working-storage, and then write the processing
code in the procedure division. In this instance you could use a perform..until.
Wow...that was a long answer. Assume a numeric named II:
Perform varying II from 1 by 1
until II > NUMBER-OF-OCCURS
If Value-1 (II) = Known-Value-1
Move New-Value-2 to Value-2 (II)
End-If
End-Perform
Related
i want to delete a specific item then subtract 1 from all the following item-id so it would look like something like this:
item-id item-name qty price
[01] Item 1 10 99
[02] Item 2 10 99
[03] Item 3 10 99
[04] Item 4 33 23
[05] Item 5 22 33
-Delete item-id 03
new output:
item-id item-name qty price
[01] Item 1 10 99
[02] Item 2 10 99
[03] Item 4 33 23
[04] Item 5 22 33
ive tried something like this the delete works correctly i just dont know how to subtract 1 from all the following item-id's
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INVENTORY
ASSIGN TO 'C:\Users\User\Desktop\FINALS\inventory.dat'
ORGANIZATION IS INDEXED
ACCESS MODE IS RANDOM
RECORD KEY IS ITEM-ID.
FILE SECTION.
FD INVENTORY.
01 FILE-INVENTORY.
02 ITEM-ID PIC 9(2).
02 ITEM-NAME PIC X(25).
02 QTY PIC Z99.
02 PRICE PIC ZZZ9.00.
WORKING-STORAGE SECTION.
01 WS-INVENTORY.
02 WS-ID PIC 9(2).
02 WS-GA PIC X(25).
02 WS-QTY PIC 999.
02 WS-PRC PIC 9999.00.
01 WS-EOF PIC A(4).
PROCEDURE DIVISION.
DEL-ITEM.
OPEN I-O INVENTORY
DISPLAY " ENTER ID OF THE PRODUCT YOU WANT TO DELETE"
DISPLAY " ITEM ID: " WITH NO ADVANCING
ACCEPT ITEM-ID
MOVE ITEM-ID TO WS-ID
DELETE INVENTORY
INVALID KEY
DISPLAY "ITEM DOES NOT EXIST"
END-DELETE
MOVE WS-ID TO ITEM-ID
READ INVENTORY NEXT INTO WS-INVENTORY
NOT AT END PERFORM ID-CHECK UNTIL WS-EOF = 'TRUE'
AT END MOVE 'TRUE' TO WS-EOF
CLOSE INVENTORY
ID-CHECK.
SUBTRACT 1 FROM WS-ID GIVING ITEM-ID REWRITE FILE-INVENTORY.
When using DELETE to remove a record, the DELETE statement must be preceded by a successful READ statement. For example,
READ INVENTORY KEY ITEM-ID
INVALID KEY
SET some-error-condition TO TRUE
NOT INVALID KEY
DELETE INVENTORY
more tests for errors
END-DELETE
END-READ
After successfully deleting the record, a loop is needed to change the prime record key of the remaining records.
Note that when changing the prime record key, REWRITE cannot be used. For ACCESS MODE IS RANDOM, use something like the following as a more complete example,
01 WS-DELETE-KEY PIC 99.
01 WS-DELETE-STATUS PIC 9 VALUE 0.
88 RECORD-NOT-FOUND VALUE 1.
88 RECORD-DELETED VALUE 2.
88 DELETE-FAILED VALUE 3.
88 NO-MORE-RECORDS VALUE 4.
ACCEPT WS-DELETE-KEY
PERFORM DELETE-RECORD
IF RECORD-DELETED
ADD 1 TO WS-DELETE-KEY
PERFORM CHANGE-PRIMARY-KEY *> for the remaining records
VARYING WS-DELETE-KEY FROM WS-DELETE-KEY BY 1
UNTIL NO-MORE-RECORDS
END-PERFORM
END-IF
.
DELETE-RECORD.
MOVE WS-DELETE-KEY TO ITEM-ID
READ INVENTORY KEY ITEM-ID
INVALID KEY
SET RECORD-NOT-FOUND TO TRUE
NOT INVALID KEY
DELETE INVENTORY
INVALID KEY
SET DELETE-FAILED TO TRUE
NOT INVALID KEY
SET RECORD-DELETED TO TRUE
END-DELETE
END-READ
.
CHANGE-PRIMARY-KEY.
MOVE WS-DELETE-KEY TO ITEM-ID
READ INVENTORY KEY ITEM-ID
INVALID KEY
SET NO-MORE-RECORDS TO TRUE
NOT INVALID KEY
DELETE INVENTORY
SUBTRACT 1 FROM ITEM-ID
WRITE FILE-INVENTORY
END-READ
This assumes that all remaining records are sequentially numbered and that the failure to read a record means there are no more records.
It may be wise to add additional checks in CHANGE-PRIMARY-KEY for other errors after the DELETE and WRITE statements.
For ACCESS MODE IS DYNAMIC the code is similar but could use START and READ ... NEXT statements.
You probably shouldn't be doing this. It's almost always a bad idea to change a primary key, because it can result in undefined behavior, i.e. you could mess up any other programs that use that file, especially if they have it open concurrently. It also could create a race condition. To be totally safe, kill all other running processes that could be potentially accessing the file using OS SYSTEM calls, open the input file with a lock, open an output file, re-write the file with the new keys under a different name (skipping that record of course), close the output file, close the input file, delete the input file, then rename the output file to the original name. Then you can restart any processes that use it.
A primary key isn't meant to be a meaningful data value, if it is, it is a "smell" that perhaps you should rethink your schema design. If your goal is to read an index file sequentially, then open it with ACCESS IS SEQUENTIAL and READ NEXT RECORD. That way it won't matter what the explicit key values are, or if there are gaps. if you are reading it later with ACCESS IS RANDOM, just include an INVALID KEY clause in your read to handle the missing key. What if there is another index file that has the deleted record key saved in a field as a foreign key? If so, you have just created an orphan and blown your referential integrity.
As a matter of fact, before doing this, you need to know for sure that this is not the case, otherwise, you should delete any other index file records that reference this one as a cascade, or check any other files that might have this key as a foreign key, and not allow the delete if they do, assuming you are in full control of the schema. Cheers!
I'm trying to achieve the following row numbering:
Count
01
A
[A
02
A
03
A
So basically any line thats blank or starts with a [ is ignored in the count
I've tried modifying this formula so that it also ignores cells that start with a [
={"Sr. No.";ArrayFormula(ifna(vlookup(row(B2:B),{filter(row(B2:B),B2:B<>""),sequence(counta(B2:B),1)},2,0)))}
The above works fine but when I added in regexmatch(B2:B, "^[^\[]) ie.
={"Sr. No.";ArrayFormula(ifna(vlookup(row(B2:B),{filter(row(B2:B),B2:B<>"",regexmatch(B2:B, "^[^\[])),sequence(counta(B2:B),1)},2,0)))}
It fails :-(
Any help/alternate approaches would be much appreciated
Explanation:
The filter and sequence formulas with the added condition [ now have different number of columns (in my example, 4 vs 5), thus returning an error.
Solution:
This can be fixed by adding -countif(LEFT(B2:B),"[") to the sequence formula:
={"Sr. No.";ArrayFormula(ifna(vlookup(row(B2:B),{filter(row(B2:B),B2:B<>"",LEFT(B2:B)<>"["),sequence(counta(B2:B)-countif(LEFT(B2:B),"["),1)},2,0)))}
Please note that I used LEFT instead of regex, it does the same text condition.
Sample:
sample data
01 A AA
01 A BB
02 B CC
03 A DD
03 A EE
the primary key is first column.
the first column and second column are common value.
the last column is personal value.
i want to merge rows in the first column and second column when the value of the first column is change.
my way is
first, write in fastreport's code using 'if' command.
second, use 'groupheader' and add the common columns in the section.
however, the first way have a problem that i don't know how to control index.
the second way is the groupheader's columns overflow PageFooter when a group end at the end of a page and the other group start at the first of next page.
please..... answer me...TTTTTT!
the first box is Groupheader's columns and the second box is overflowed data.
Try to use TfrxDBCrossView object
I am wondering if what I want to do can be accomplished in COBOL. I am trying to read in hospital and patient data from a file that is not in order. Instead of using Sort (like everyone would in real life), I am to use an array to somehow sort the data that comes in. At the end I'm supposed to print out a report to another file grouped by hospital number.
So,
Hospital #
patient 018
patient 020
total for hospital #
Hospital #
patient 011
patient 009
total for hospital #
All of these hospital numbers is to be between 1 and 30 and patient numbers are between 1 and 20. I have a pretty good idea about what to do and how to sum up patient balances, but what do you think of going about it this way:
Read in data to an array (this would obviously be more than 1 dimension). At this point the data is unsorted in the array. I don't think it matters if it's sorted inside the array as long as it comes out on the report sorted. Does this sound right? And yes, this is for an assignment. Any tips or recommendations, feedback that could be offered without giving the answer?
EDIT:
Okay, so I tried to create a 2d type array that would have the fields I needed to get the job done (hos num, pat name, pat num, pat amnt). And of course I want to add each patient amount to a running total for hospital subtotal.
Here is my array:
01 HospArray value spaces.
05 hosnum occurs 30 times indexed by subsa.
07 patnum occurs 20 times indexed by subsb.
10 patname PIC X(20).
10 patamt PIC 9(7)v99.
07 hossubtotal PIC 9(7)v99.
While reading in the file and moving it to my working storage fields, I attempt to do two perform varying loops like this:
perform varying subsa from 1 by 1 until subsa > 30
move hos-num-ws to hosnum (subsa)
perform varying subsb from 1 by 1 until subsb > 20
move pat-name-ws to patname(subsa, subsb)
move pat-amnt-od-ws to patamt(subsa, subsb)
add patamt(subsa, subsb) to hossubtotal (suba)
end-perform
end-perform
For some reason this won't compile and it gives the error of: Unexpected ADD and I am not sure why. I am using openCobol. I don't have a ton of experience so I'm not sure why this isn't compiling. I am still not sure if I am going in the right direction. I know I want to say, why the count is on a given hospital number move patient data to variables, and then somehow I should know when the current hospital number is done. Output the hospital subtotal, then repeat the process again.
"All of these hospital numbers is to be between 1 and 30 and patient numbers are between 1 and 20"
So use those values as "subscripts" into a table. Hopital number (1 to 30) for first level, patient number (1 to 20) for second. Everything set to, say, space beforehand.
When you come to list out, list hopitals which are not space (the value of the subscript at the time can tell you which, or instead store the hospital) and all their patients which are not space.
However, your sample output has patients "somewhat beyond" 1-20 :-)
EDIT:
There are several things wrong with your code.
When loading the table, you will just be adding one hospital/patient combination at a time.
When extracting the data from your table, you will be "looping" through it.
You move the hospital number to the table, but you are moving it to a group level, so will obliterate anything under that entry.
I've already mentioned the typo in a comment. When you get a compile message like that, you have to go with "well, something is wrong on or above this line".
You are doing your running total without having set the starting value to zero.
You don't need to do the running total as you go along, you can do it as you list out the data.
A couple of other things. You call your indexes "subsa" and "subsb". This is both not "meaningful" and confusing (they are indexes, subscripts are something slightly different).
You should be consistent with abbreviations. You should work at getting meaningful data-names.
Here's some example snippets. I've put some time into naming and formatting. You may think that this seems like a lot of effort, but that's what being capable with your editor is about. I didn't type any of the long names more than once, but I bet you typed out each of your short ones.
01 HospArray value spaces.
05 FILLER occurs 30 times
indexed by I-Hospital-Entry.
10 HA-Hospital-Entry.
15 HA-Hospital-Number pic xx.
88 HA-hospital-not-present
VALUE SPACE.
15 FILLER occurs 20 times
indexed by I-Patient-Entry.
20 HA-Patient-Entry.
25 HA-Patient-Number pic xx.
88 HA-Patient-not-present
VALUE SPACE.
25 HA-Patient-Name PIC X(20).
25 HA-Patient-Payment-Amount PIC 9(7)v99.
01 Hospital-Sub-Total PIC 9(7)v99.
01 W-Patient-Name pic x(20).
01 Patient-Payment-Amount pic 9(7)v99.
01 Hospital-Number.
05 Hospital-Number-N pic 99.
01 Patient-Number.
...
SET I-Hospital-Entry TO Hospital-Number-N
SET I-Patient-Entry TO Patient-Number-N
MOVE Hospital-Number TO HA-Hospital-Number
( I-Hospital-Entry )
MOVE Patient-Number TO HA-Patient-Number
( I-Hospital-Entry
I-Patient-Entry )
MOVE W-Patient-Name TO HA-Patient-Name
( I-Hospital-Entry
I-Patient-Entry )
MOVE Patient-Payment-Amount TO HA-Patient-Payment-Amount
( I-Hospital-Entry
I-Patient-Entry )
...
to output the results
PERFORM LIST-PATIENTS-BY-HOSPITAL
GOBACK
.
LIST-PATIENTS-BY-HOSPITAL.
perform
varying I-Hospital-Entry
from 1 by 1
until I-Hospital-Entry > 30
IF HA-hospital-not-present ( I-Hospital-Entry )
CONTINUE
ELSE
PERFORM LIST-PATIENTS
DISPLAY Hospital-Sub-Total
END-IF
move HA-Hospital-Number
( I-Hospital-Entry )
TO Hospital-Number
end-perform
.
LIST-PATIENTS.
perform
varying I-Patient-Entry
from 1 by 1
until I-Patient-Entry > 20
IF HA-hospital-not-present ( I-Hospital-Entry )
CONTINUE
ELSE
PERFORM PATIENT-DETAILS
END-IF
DISPLAY Hospital-Sub-Total
end-perform
.
PATIENT-DETAILS.
move HA-Patient-Name
( I-Hospital-Entry
I-Patient-Entry ) TO W-Patient-Name
move HA-Patient-Payment-Amount
( I-Hospital-Entry
I-Patient-Entry ) TO Patient-Payment-Amount
add Patient-Payment-Amount TO Hospital-Sub-Total
the "target" fields here can be in a formatted line for printing/DISPLAYing.
.
The example patient numbers you gave are way out of the 1 to 20 range. I'm guessing that
you really meant to say there are between 1 and 20 patients per hospital, not that the patient numbers
fall into the range of 1 through 20.
I am also thinking that your statement: "somehow sort the data that comes in" is the real objective here.
The data from the input file are not sorted but you need to get them sorted. There are a few ways
of doing this:
Read all the data into a table, then sort the table using an external SORT program or an internal
sort you write yourself (e.g. bubble sort or something like that). Going this route would involve
doing two sorts, one for each dimension of the table (eg. Sort by hospital and then by patient within hospital)
Read a record and add it into the table such that the table is always sorted. This means being able to insert
a new item at the top of the table, between two existing items in the table or at the end of the table.
Again, this would be a two dimensional process: Add hospital, add patient within hospital
The approach suggested by Bill Woodger would work well only if the hospital and patient numbers fall within
a very small range (as you suggested they might).
At any rate you now have three suggestions to follow up on. Since this is a homework assignment I would base
my choice on what course material was being taught around this assignment. If internal/external sorting was
emphasized, then go the sorting route. If multi dimensional table declaration and manipulation were
recent topics then got with the build and keep the table sorted. If hashing came up then consider Bill's
suggestion.
I am doing a flat file writing on cobol.
but when the variable is null , it will not fill with spaces. Please help.
Here is some of the part of flat file structure declaration.
01 Fs-IL494-REC.
03 FX-IL494-TRXN-1-10 PIC X(410) VALUE SPACES.
01 Wx-TRXN-INFO-BUF PIC X(410) VALUE SPACES.
01 Ws-TRXN-INFO REDEFINES Wx-TRXN-INFO-BUF OCCURS 10 TIMES.
03 Wx-TRXN-DT PIC X(8).
03 Wx-TRXN-CDE PIC X(3).
03 W9-TRXN-AMT PIC S9(13)V9(2)
SIGN LEADING SEPARATE.
03 Wx-TRXN-DESC PIC X(14).
Doing some query to retrive the records from database.
INITIALIZE Wx-TRXN-INFO-BUF.
INITIALIZE FX-IL494-TRXN-1-10.
ADD 1 TO W9-ARR-CNT
MOVE F9-IRC-TXN-DT TO Wx-TRXN-DT(W9-ARR-CNT)
MOVE F9-IRC-TXN-CDE TO Wx-TRXN-CDE(W9-ARR-CNT)
MOVE F9-IRC-TXN-AMT TO W9-TRXN-AMT(W9-ARR-CNT)
MOVE FX-IRC-TXN-DESC TO Wx-TRXN-DESC(W9-ARR-CNT)
MOVE Wx-TRXN-INFO-BUF TO FX-IL494-TRXN-1-10
My assumptions:
This is SQL (DB/2 probably)
You are doing a SELECT INTO :host-variable
The host-variable is the thing you expect to be set to SPACES when the corresponding database table column contains a NULL value.
If the above is correct, the problem is that when a NULL value is selected off of the database, the corresponding host-variable is not updated. It will retain whatever value it had before the query was executed.
You may need to add a null value indicator to your query. When the null value indicator is set to a value less than zero (often -1) the corresponding host-variable is unchanged. This is the pattern you should be using:
EXEC SQL
SELECT column-name-1,
column-name-2
INTO :host-var-1 :null-ind-1,
:host-var-2 :null-ind-2
FROM some-table
WHERE bla bla bla...
END-EXEC
The "extra" variables null-ind-1 and null-ind-2 should be declared as S9(4) USAGE COMP. Notice that comma is "missing" between the host variable and the null indicator. The null indicator variables will be assigned a value less than zero when the corresponding column-name-1 or column-name-2 contain NULL values. Should that be the case, then host-var-1 and host-var-2 will remain unchanged (i.e. retain whatever values they had before the EXEC SQL.
In your code after the EXEC SQL you should be doing something like:
IF null-ind-1 < ZERO
MOVE SPACES TO host-var-1
END-IF
IF null-ind-2 < ZERO
MOVE SPACES to host-var-2
END-IF
I have also seen programmers simply initialize all host variables before doing the EXEC SQL to whatever they would want in event of a NULL column value and not bother with null indicators on the query (not hard to figure out why that would work once you know that DB2 will not update the host variable in event of a NULL value)..
Initialize is tied to the value clause, and it's behavior can be quirky and annoying.
Far better to simple "Move spaces to my-record" before you do your read...