Multiple Record Processing

In this section:

Multiple record processing enables you to process multiple segment instances at one time. One important application is the use of multiple record processing with the FIDEL facility to enable the terminal operator to add, update, or delete several segment instances on one screen. This section discusses multiple record processing based on this application. However, you can apply the principles stated here to other applications as well.

Usually, a MODIFY request using FIDEL prompts you for a key field value, then uses the value to retrieve one segment instance. After you modify the instance, you enter the key field value to retrieve the next instance. This way, you modify segment instances one at a time.

Multiple record processing causes the request to retrieve multiple segment instances before FIDEL displays instance values. Each time the request retrieves an instance, it stores the instance values in a work area in memory called the Scratch Pad Area. The request continues to retrieve instances until it reaches a specified number.

After the request has retrieved the instances, FIDEL reads the instance values from the Scratch Pad Area and displays them all on one screen. The user can update these values and transmit the updated values back to the data source with one press of the Enter key.

Note: Text fields cannot be put into the Scratch Pad (HOLD).

You may also design a request that adds several instances at one time, or a request that both updates existing instances and adds new ones all on the same screen.

The REPEAT Method describes multiple record processing using the REPEAT statement. This method requires only that you know the fields you want to process. However, it only enables you to process instances from one segment at a time.

Manual Methods discusses manual methods that require you to know how instances are stored in the Scratch Pad Area. These methods are more powerful and enable you to process multiple segments at one time.

The REPEAT Method

In this section:

One REPEAT statement collects segment instances and loads them into the Scratch Pad Area; another REPEAT statement retrieves the instances from the Area and uses them to modify the data source. This method does not require you to know how the instances are stored in the Area; however, you must process the instances sequentially, and you can process only one segment at one time.

Multiple record processing has four phases. They are:

  1. Selection. The request selects the parent instance of the instances to be processed.
  2. Collection. The request retrieves multiple segment instances and stores their data values in the Scratch Pad Area.
  3. Display. The FIDEL facility displays the data on one screen for editing.
  4. Modification. The request uses the edited data values to modify the data source.

The Selection Phase: Selecting the Parent Instance

To modify multiple instances in a segment, you must first identify the parent instance. (If you are modifying the root segment, skip this phase and start with The Collection Phase: Storing Instances in a Buffer.) Do this as you would any other request.

For example, the beginning of this request identifies an employee ID in the EMPLOYEE data source, allowing you to modify the employee's child segment instances:

MODIFY FILE EMPLOYEE
CRTFORM LINE 2
"**************************************"
"* MONTHLY PAY UPDATE                 *"
"**************************************"
" "
"ENTER EMPLOYEE'S ID: <EMP_ID"
 
MATCH EMP_ID
  ON NOMATCH REJECT
  ON MATCH GOTO COLLECT

If you are using multiple record processing only to create new instances, skip the collection phase and proceed directly to the display phase. The following MATCH statement adds a new employee ID to the data source. It then branches to the case NEWADDRESS where the display phase prompts the user for all the employees' addresses:

MODIFY FILE EMPLOYEE
CRTFORM
"ENTER EMPLOYEE'S ID: <EMP_ID"
MATCH EMP_ID
  ON MATCH REJECT
  ON NOMATCH INCLUDE
  ON NOMATCH GOTO NEWADDRESS

The Collection Phase: Storing Instances in a Buffer

How to:

Reference:

During the collection phase, the request retrieves multiple segment instances and stores their values in the Scratch Pad Area.

After identifying the parent instance, read the child instances into the Scratch Pad Area (if you are modifying the root segment, reading the instances into the Area is your first step). You do this using the REPEAT statement, which the request executes repeatedly. Each time the request executes a REPEAT statement, the phrases in the statement retrieve one segment instance and store its data values in the Area.

Syntax: How to Use a REPEAT Statement

The syntax of the REPEAT statement is

REPEAT {*|count}[TIMES] [MAX limit] [NOHOLD]
  .
  . 
phrases 
  .
  .
ENDREPEAT

where:

count

Is an integer or temporary integer field determining the number of times the request executes the REPEAT. This value can be between 0 and 32,767, but should be no smaller than the number of segment instances you want to display on the FIDEL screen.

If this value is 0, the request does not execute the REPEAT (this allows you to skip a REPEAT if you are using a temporary field for this parameter). If the value is an asterisk, the REPEAT is executed 65,535 times. Once the REPEAT begins execution, the value cannot be changed.

TIMES

Is an optional word, which you can add to enhance readability.

limit

Is an integer specifying the maximum number of times the request can execute the REPEAT. Specify this parameter only if you are using a temporary field for the count parameter.

NOHOLD

Is an option that enables you to use REPEAT as a simple loop that executes any group of MODIFY statements repeatedly.

phrases

Are the MODIFY statements to be executed within the REPEAT statement. Each phrase must begin on a new line.

ENDREPEAT

Ends the statement. This phrase must be on a line by itself.

There are three types of REPEAT statements:

  • Stacking REPEAT statements. These statements contain HOLD phrases that stack data into the Scratch Pad Area. They appear in the collection phase of multiple record processing.
  • Retrieving REPEAT statements. These statements retrieve data placed in the Scratch Pad Area by the stacking REPEAT statements. They usually appear in the modification phase and in validation routines in multiple record processing.
  • Simple REPEAT statements. These statements consist of any combination of MODIFY statements to be executed repeatedly. You indicate a simple repeat statement by specifying the NOHOLD option in the REPEAT phrase. Simple REPEAT statements neither stack data nor retrieve data from the Scratch Pad Area.

FOCUS determines the type of REPEAT statement in the following manner:

  • If the statement specifies the NOHOLD option, it is a simple REPEAT statement.
  • If the statement contains a HOLD phrase, it is a stacking REPEAT statement.
  • If the statement neither specifies the NOHOLD option nor contains a HOLD phrase, it is a retrieving REPEAT statement.

The REPEAT statement can stand by itself, or it can be part of an ON MATCH, ON NOMATCH, ON NEXT, or ON NONEXT phrase in a MATCH or NEXT statement. For example:

REPEAT 12 TIMES
ON MATCH REPEAT 6
ON NEXT REPEAT BUFCOUNT MAX 10

Note: You cannot nest REPEAT statements; one statement must end before another can begin.

Two GOTO phrases especially apply to REPEAT statements. They are:

  • GOTO ENDREPEAT. This phrase branches processing to the end of the REPEAT statement, increments the counter by 1, and executes the request REPEAT again.
  • GOTO EXITREPEAT. This phrase branches processing to the first executable statement following the REPEAT loop.

This REPEAT saves the first five pay dates and monthly pay amounts in the EMPLOYEE data source in the Scratch Pad Area:

CASE COLLECT
REPEAT 5 TIMES
  NEXT PAY_DATE
    ON NEXT HOLD PAY_DATE GROSS
    ON NONEXT GOTO EXITREPEAT
ENDREPEAT
GOTO DISPLAY
ENDCASE

Note the ON NONEXT GOTO EXITREPEAT phrase. This specifies that if there are less than five employee IDs in the segment chain, the request will branch to the next statement after the REPEAT. If the ON NONEXT phrase was not included, the request would automatically branch back to the beginning of the request.

Syntax: How to Store Instances With the HOLD Phrase

The REPEAT statement retrieves instances using MATCH and NEXT statements. Each time the REPEAT retrieves an instance, you may store the instance values in the Scratch Pad Area. Do this with the phrase

HOLD [SEG.]field-1 field-2 ... field-n

where field-1 through field-n are the data fields whose values you want to save in the Scratch Pad Area. The specified fields can be data source fields or temporary fields. The data source fields must exist either in the instance or in a parent instance along the segment path (the parent of the instance, the parent's parent, and so on to the root segment). For example, the phrase

HOLD EMP_ID FIRST_NAME LAST_NAME CURR_SAL

stores the employee IDs, first and last names, and salaries of each retrieved instance in the Scratch Pad Area.

If you want to save the values of all the data fields in the instance, specify just one field with the SEG. prefix affixed to the front of the field name.

HOLD stores the fields whether they are active or inactive. To ensure that the fields placed in the Scratch Pad Area are active, use the ACTIVATE phrase described in Active and Inactive Fields.

The HOLD phrase can stand by itself, or it can be part of an ON MATCH, ON NOMATCH, ON NEXT, or ON NONEXT phrase in a MATCH or NEXT statement. If you use HOLD in ON NOMATCH and ON NONEXT phrases, you may specify only temporary fields and fields in parent instances along the segment path. If the list of fields is too long to fit on one line, repeat the word HOLD for each line you need. Some examples are:

HOLD EMP_ID LAST_NAME FIRST_NAME DEPARTMENT
HOLD CURR_JOBCODE ED_HRS
 
ON MATCH HOLD EMP_ID DEPARTMENT CURR_SAL
 
ON NONEXT HOLD DEPCODE

When a REPEAT statement containing a HOLD phrase begins execution, FOCUS clears the Scratch Pad Area of data stored from previous REPEATs.

The following is a piece of a MODIFY request that executes the collection phase:

CASE COLLECT
REPEAT 5 TIMES
  NEXT PAY_DATE
    ON NEXT HOLD PAY_DATE GROSS
    ON NONEXT GOTO DISPLAY
ENDREPEAT
GOTO DISPLAY
ENDCASE

Reference: The REPEATCOUNT and HOLDCOUNT Variables

Two variables assume values during the collection phase. These are:

  • The REPEATCOUNT variable. This variable contains the value of the REPEAT counter.
  • The HOLDCOUNT variable. This variable contains the current number of instances stored in the Scratch Pad Area.

If you design your request with Case Logic, you can test and branch on these variables. The following IF statement branches to the TOP case if the preceding REPEAT did not retrieve any segment instances:

IF HOLDCOUNT EQ 0 GOTO TOP

Please note the following values that the REPEATCOUNT and HOLDCOUNT variables take under these circumstances:

  • When a REPEAT statement begins execution, REPEATCOUNT is set to 1.
  • If a REPEAT is set to execute 0 times, REPEATCOUNT is set to 0.
  • If the REPEAT beginning execution contains HOLD phrases, the Scratch Pad Area is cleared and HOLDCOUNT is set to 0. If the REPEAT does not contain HOLD phrases, HOLDCOUNT is unchanged.
  • At each repetition of the REPEAT, REPEATCOUNT is increased by one. After each HOLD phrase is executed, HOLDCOUNT is increased by one.
  • The REPEATCOUNT variable maintains its value after the REPEAT completes execution until the next REPEAT, even if the request branched from the REPEAT with a GOTO phrase.

    Note: A CRTFORM displaying records in the Scratch Pad Area can change the HOLDCOUNT value. For this reason, you may want to store the HOLDCOUNT value in a temporary field for use later in the request. For example, this COMPUTE statement saves the value of the HOLDCOUNT field in the temporary field BUFFNUMBER:

    COMPUTE BUFFNUMBER/I5 = HOLDCOUNT;

The Display Phase: Displaying Instances in One CRTFORM

How to:

After the request stores the segment instance values in the Scratch Pad Area, you display the values on one screen using the FIDEL facility (see Designing Screens With FIDEL). Since you use the same field names for all instances (multiple record processing can only modify one segment at a time), you must distinguish between instances. To do this, add subscripts to the fields using the form.

field(n)

where n (the subscript) is an integer greater than 0. The subscript indicates the instance that a field belongs to in the order that the instances are read from the Scratch Pad Area.

For example, this CRTFORM displays the employee IDs, departments, and salaries of five segment instances numbered 1 through 5:

CASE DISPLAY
IF HOLDCOUNT EQ 0 GOTO TOP;
COMPUTE
  BUFFNUMBER/I5=HOLDCOUNT;
CRTFORM LINE 9
   " MONTHLY PAY FOR <D.FIRST_NAME <D.LAST_NAME"
   " "
   " PAY DATE         AMOUNT PAID"
   " --------         -----------"
   "<D.PAY_DATE(1)    <T.GROSS(1)>"
   "<D.PAY_DATE(2)    <T.GROSS(2)>"
   "<D.PAY_DATE(3)    <T.GROSS(3)>"
   "<D.PAY_DATE(4)    <T.GROSS(4)>"
   "<D.PAY_DATE(5)    <T.GROSS(5)>"
GOTO UPDATE
ENDCASE

Note the D. prefix (display) that displays protected field values, and the T. prefix (turnaround) that displays field values to be updated. Display fields and turnaround fields are described in Designing Screens With FIDEL. Make all turnaround fields non-conditional; that is, end the field name with a right caret.

Once you have updated the values, you can transmit all the changes at one time by pressing the Enter key. These changes update the appropriate instances in the Scratch Pad Area. The request then branches to the modification phase (the UPDATE case), where your changes are entered into the data source. The CRTFORM may then prompt you for the next parent instance or may display the next set of multiple instances for you to change.

For example, a request that updates employee's monthly pay prompts you for an employee ID. This employee has eight pay dates recorded. The screen displays the first five pay dates. Make your adjustments and press Enter. The screen displays the last three pay dates. Make your adjustments and press Enter. The request then prompts you for the next employee ID.

You may add subscripts to fields only in CRTFORMs, not in REPEATs. REPEATs that follow the CRTFORMs process the fields in the order of the instances in the Scratch Pad Area, one at a time.

Procedure: How to Position the Cursor on Specific Field Values

You can design the request so that the cursor is automatically positioned on a particular field value on the FIDEL screen. To do this, set the CURSOR variable equal to the field name, as described in Designing Screens With FIDEL. If the fields are subscripted, set a field called CURSORINDEX equal to the value of the subscript. For example, this COMPUTE statement places the cursor on the field CURR_SAL(3):

COMPUTE
  CURSOR/A12 = 'CURR_SAL';
  CURSORINDEX = 3;

These cursor-positioning variables are useful when you perform validation tests on data entered on the FIDEL screen. After the CRTFORM, write a REPEAT statement for each field you are validating. Specify as many executions for the REPEAT as the highest subscript in the CRTFORM.

In the REPEAT statement:

  • Set the CURSOR variable equal to the name of the field you are validating.
  • Set the CURSORINDEX variable equal to the REPEATCOUNT variable. This sets the CURSORINDEX variable to the subscript of the field being validated.
  • Validate the field.
  • If a field value proves invalid, branch back to the CRTFORM using Case Logic. The CURSOR and CURSORINDEX variables will position the cursor at the invalid value.

Note: Remember to assign the CURSOR variable a format of A12 and the CURSORINDEX variable a format of I5.

This is a sample case validating the CURR_SAL field:

CASE DISPLAY
CRTFORM
"EMPLOYEE      SALARY            DEPARTMENT"
"--------      ------            --------- "
"<D.EMP_ID(1)  <T.CURR_SAL(1)>   <T.DEPARTMENT(1)>"
"<D.EMP_ID(2)  <T.CURR_SAL(2)>   <T.DEPARTMENT(2)>"
"<D.EMP_ID(3)  <T.CURR_SAL(3)>   <T.DEPARTMENT(3)>"
"<D.EMP_ID(4)  <T.CURR_SAL(4)>   <T.DEPARTMENT(4)>"
"<D.EMP_ID(5)  <T.CURR_SAL(5)>   <T.DEPARTMENT(5)>"
 
REPEAT 5 TIMES
  COMPUTE
    CURSOR/A12 = 'CURR_SAL';
    CURSORINDEX/15 = REPEATCOUNT;
  VALIDATE
    SALTEST = IF CURR_SAL GT 50000 THEN 0 ELSE 1;
    ON INVALID TYPE
       "THIS SALARY ENTERED WAS TOO HIGH"
       "PLEASE RE-ENTER"
    ON INVALID GOTO DISPLAY
ENDREPEAT
ENDCASE

The Modification Phase

After the user has entered changes on a FIDEL screen, the request uses the data to update instances in the Scratch Pad Area and to add new ones. To transfer the changes from the Area to the data source, prepare a REPEAT statement that modifies a data source instance on each pass.

This REPEAT updates the EMPLOYEE data source using data entered on the FIDEL screen shown in the previous section, The Display Phase: Displaying Instances in One CRTFORM. The REPEAT should execute as many times as there are instances in the Scratch Pad Area. This number was stored in the HOLDCOUNT variable. However, the HOLDCOUNT value can be changed by the CRTFORMs that display records in the Area. Therefore, you should store the HOLDCOUNT variable in a temporary field in the display phase before the CRTFORM. (This is shown in the example at the beginning of the section mentioned above.) This field can then set the number of times that the REPEAT statement executes.

At each pass, the REPEAT statement retrieves one instance from the Scratch Pad Area. It can then match on key fields in the instance to locate the corresponding instance in the data source (or determine that such an instance does not exist), then update the data source instance or add a new one.

In this example, the case UPDATE updates the data source instances, then branches back to the collection phase (COLLECT case). The collection phase reads the next five employee pay dates, which you can then change on the CRTFORM. This cycle continues until all the employee's pay dates have been read. You then enter the ID of the next employee. The number of instances in the Scratch Pad Area is contained in the temporary field BUFFNUMBER:

CASE UPDATE
REPEAT BUFFNUMBER
  MATCH PAY_DATE
    ON NOMATCH INCLUDE
    ON MATCH UPDATE GROSS
ENDREPEAT
GOTO COLLECT
ENDCASE
 
DATA VIA FI3270
END

Example: Using Multiple Record Processing (REPEAT Method)

The sample request on the next page updates the monthly pay of employees. The CRTFORM in the display phase displays the data for the five months in which the employee was paid. After you update the monthly pay of these five months, the display phase displays the next five months. This continues until it displays all the months recorded for that employee. The request then prompts for the next employee ID.

The request is as follows:

MODIFY FILE EMPLOYEE
CRTFORM LINE 2
"**************************************"
"*MONTHLY PAY UPDATE*"
"**************************************"
" "
"ENTER EMPLOYEE'S ID: <EMP_ID"
 
MATCH EMP_ID
  ON NOMATCH REJECT
  ON MATCH GOTO COLLECT
 
CASE COLLECT
REPEAT 5 TIMES
  NEXT PAY_DATE
     ON NEXT HOLD PAY_DATE GROSS
     ON NONEXT GOTO DISPLAY
ENDREPEAT
GOTO DISPLAY
ENDCASE
CASE DISPLAY
IF HOLDCOUNT EQ 0 GOTO TOP;
COMPUTE
  BUFFNUMBER/I6=HOLDCOUNT;
CRTFORM LINE 9
" MONTHLY PAY FOR <D.FIRST_NAME <D.LAST_NAME"
" "
"PAY DATE               AMOUNT PAID"
"---------------        -----------"
"<D.PAY_DATE(1)         <T.GROSS(1)>"
"<D.PAY_DATE(2)         <T.GROSS(2)>"
"<D.PAY_DATE(3)         <T.GROSS(3)>"
"<D.PAY_DATE(4)         <T.GROSS(4)>"
"<D.PAY_DATE(5)         <T.GROSS(5)>"
GOTO UPDATE
ENDCASE
CASE UPDATE
REPEAT BUFFNUMBER
  MATCH PAY_DATE
    ON NOMATCH INCLUDE
    ON MATCH UPDATE GROSS
ENDREPEAT
GOTO COLLECT
ENDCASE
DATA VIA FI3270
END

Manual Methods

In this section:

This section discusses manual methods of multiple record processing. These methods allow you to manipulate individual records in the Scratch Pad Area and to process instances from multiple segments at one time.

Manual methods depend on two temporary fields:

There are manual methods for the collection, sorting, display, and modification phases of multiple record processing. There are no manual methods for the first phase, the selection phase (discussed in Multiple Record Processing). Note, however, that if you process multiple segments that have no common parent, you must select the parent instance of each segment chain.

Initialization

Before loading instances into the Scratch Pad Area, the request may need to perform the following tasks:

  • Define the following variables with a format of I5:

    The HOLDCOUNT field. Set HOLDCOUNT equal to 0.

    The HOLDINDEX field. Set HOLDINDEX equal to 1.

    The SCREENINDEX field. Set SCREENINDEX equal to 0.

  • Use the REPOSITION statement to insure that the current position in each segment, from which instances will be loaded into the Scratch Pad Area, is at the beginning of the segment.

The following is the beginning of a MODIFY request that uses manual methods:

MODIFY FILE EMPLOYEE
CRTFORM
  "ENTER EMPLOYEE ID: <EMP_ID"
MATCH EMP_ID
  ON NOMATCH REJECT
  ON MATCH GOTO INITIAL
 
CASE INITIAL
REPEAT 1
  HOLD EMP_ID
ENDREPEAT
COMPUTE
  HOLDCOUNT/I5 = 0;
  HOLDINDEX/I5 = 1;
  SCREENINDEX/I5 = 0;
REPOSITION SALARY
REPOSITION PAY_DATE
GOTO SALCOLLECT
ENDCASE

The Collection Phase: The HOLDINDEX Field

During the collection phase, the request retrieves multiple segment instances from the data source and stores each instance as a record in the Scratch Pad Area. FOCUS assigns each record an index value equal to the current value of the HOLDINDEX field, then increments HOLDINDEX by 1. For example, if HOLDINDEX is equal to 5, then the request stores one segment instance in the Area as Record 5, the next instance as Record 6, and so on.

To store instances from multiple segments, follow this procedure:

  1. Assign each segment a range of index values (for example, assign one segment values 1 through 5, another 6 through 11, and so on).
  2. Write the request so that a separate case loads instances from each segment. Before each case executes, have a COMPUTE statement set HOLDINDEX to the index value of the first record for that segment.

To assign index values to a segment, you must know the largest number of instances you will be storing from that segment. In many applications, you will be storing an entire segment chain at a time. You then must know the size of the largest segment chain.

Note: Be sure that you set HOLDINDEX to a value less than or equal to the current value of the HOLDCOUNT field. A HOLDINDEX value greater than HOLDCOUNT generates an error that terminates the request.

For example, suppose you write a request to update both employees' salary history (SALARY) and monthly pay (GROSS), information contained in two different segments in the EMPLOYEE data source (see the diagram that follows).

To determine the size of the largest chains in both segments, enter this procedure:

TABLE FILE EMPLOYEE
COUNT SALARY AND PAY_DATE BY EMP_ID
ON TABLE HOLD
END
 
TABLE FILE HOLD
SUM MAX.SALARY AND MAX.PAY_DATE
END

The output appears as follows:

PAGE    1
MAX       MAX
SALARY    PAY_DATE
------    --------
    2      10

The report shows that the largest salary history chain consists of two instances and the largest monthly pay chain consists of ten instances. Therefore, you assign values 1 and 2 to the salary history segment and values 3 through 12 to the monthly pay segment. Schematically, the Scratch Pad Area will look like this:

1. DAT_INC(1)   SALARY(1)         -              -
2. DAT_INC(2)   SALARY(2)         -              -
3.    -            -         PAY_DATE(3)      GROSS(3)
4.    -            -         PAY_DATE(4)      GROSS(4)
5.    -            -         PAY_DATE(5)      GROSS(5)
6.    -            -         PAY_DATE(6)      GROSS(6)
7.    -            -         PAY_DATE(7)      GROSS(7)
8.    -            -         PAY_DATE(8)      GROSS(8)
9.    -            -         PAY_DATE(9)      GROSS(9)
10.   -            -         PAY_DATE(10)     GROSS(10)
11.   -            -         PAY_DATE(11)     GROSS(11)
12.   -            -         PAY_DATE(12)     GROSS(12)

To fix the index values in the request, set HOLDINDEX to the first index value assigned to a segment before loading instances from that segment. In the example above, set HOLDINDEX to 1 before loading the salary history instances, and set HOLDINDEX to 3 before loading the monthly pay instances. This reserves the proper index values for each segment.

Prepare separate cases to load instances from each segment. During the modification phase, discussed on the next page, you may plan to retrieve all records from the same segment at one time. If so, store the index value of the last instance loaded into the Scratch Pad Area from that segment (this is the HOLDINDEX value after the last instance is loaded minus one) in a field. This field will help retrieve the records in the modification phase.

For example, you are loading monthly pay instances into the Scratch Pad Area. The last monthly pay instance loaded into the Area is assigned index value 8. You then store 8 in the field LASTPAY.

This example is a request fragment that updates employees' salary histories and monthly pay:

CASE SALCOLLECT
NEXT SALARY
  ON NEXT HOLD DAT_INC SALARY
  ON NEXT GOTO SALCOLLECT
  ON NONEXT COMPUTE
     LASTSAL/I5 = HOLDINDEX-1;
     HOLDINDEX = 3;
  ON NONEXT GOTO PAYCOLLECT
ENDCASE
 
CASE PAYCOLLECT
NEXT PAY_DATE
  ON NEXT HOLD PAY_DATE GROSS
  ON NEXT GOTO PAYCOLLECT
  ON NONEXT COMPUTE
     LASTPAY/I5 = HOLDINDEX-1;
  ON NONEXT GOTO DISPLAY
ENDCASE

The three cases are:

  • The TOP case. This case selects an employee and sets the HOLDINDEX field to 1 to index the salary history instances.
  • The SALCOLLECT case. This case loads the salary history instances into the Scratch Pad Area. After the instances are loaded, the case stores the index value of the last loaded salary history instance in the field LASTSAL. It then sets the HOLDINDEX field to 3 to index the monthly pay instances.
  • The PAYCOLLECT case. This case loads the monthly pay instances into the Scratch Pad Area. After it loads the instances, it stores the index value of the last loaded monthly pay instance in the field LASTPAY. It then proceeds to the display phase.

The Display Phase: The SCREENINDEX Field

This section shows how to display a specific group of records in the Scratch Pad Area.

The REPEAT Method described how to display records in the Scratch Pad Area on a CRTFORM. The CRTFORM statement specifies the field names with subscripts that refer to the records in the Area. For example:

CRTFORM
  "MONTHLY PAY FOR <D.FIRST_NAME <D.LAST_NAME"
  " "
  "PAY DATE          AMOUNT PAID"
  "--------          -----------"
  "<D.PAY_DATE(1)    <T.GROSS(1)>"
  "<D.PAY_DATE(2)    <T.GROSS(2)>"
  "<D.PAY_DATE(3)    <T.GROSS(3)>"
  "<D.PAY_DATE(4)    <T.GROSS(4)>"
  "<D.PAY_DATE(5)    <T.GROSS(5)>"

To display a subscripted field, FOCUS adds the field subscript to the value of a field called SCREENINDEX, then uses the sum as an index value to locate a record in the Scratch Pad Area. It then displays the field value in that record. For example, if the SCREENINDEX value for the above CRTFORM is 4, FOCUS will display the PAY_DATE and GROSS values from Area records 5 through 9.

You can use this feature to scroll back and forth through the Scratch Pad Area. To scroll forward, increase the value of SCREENINDEX; to scroll backward, decrease the value of SCREENINDEX.

If you update a field value on the CRTFORM, FOCUS updates the appropriate record in the Scratch Pad Area.

Note:

  • If the request does not give SCREENINDEX a value, the default value is 0.
  • If the sum of the SCREENINDEX value and a field subscript is less than 0 or more than the current value of the HOLDCOUNT field, then the CRTFORM displays that field as blank.
  • If you use the CURSORINDEX field to place the cursor on a field value (as described in The REPEAT Method), the CURSORINDEX value refers to the field subscript, not the index value.

This sample case displays blocks of eight records stored in the Scratch Pad Area. The first record in each block is a monthly pay instance. The remaining seven records are deductions taken from the employee's paycheck. The case is:

CASE DISPLAY
IF HOLDCOUNT EQ 0 THEN GOTO TOP;
COMPUTE
  PFKEY/A4 = ' ';
  EMPID/A9 = EMP_ID;
  DED_AMT/D12.2M = DED_AMT;
CRTFORM LINE 1
  "DEDUCTION RECORD SCREEN"
  " "
"  EMPLOYEE: <D.EMPID      PAY DATE: <D.PAY_DATE(1)"
" "
"1. <D.DED_CODE(2)    <T.DED_AMT(2)>"
"2. <D.DED_CODE(3)    <T.DED_AMT(3)>"
"3. <D.DED_CODE(4)    <T.DED_AMT(4)>"
"4. <D.DED_CODE(5)    <T.DED_AMT(5)>"
"5. <D.DED_CODE(6)    <T.DED_AMT(6)>"
"6. <D.DED_CODE(7)    <T.DED_AMT(7)>"
"7. <D.DED_CODE(8)    <T.DED_AMT(8)>"
" "
"PRESS PF4 TO DISPLAY THE NEXT EMPLOYEE"
"PRESS PF5 TO DISPLAY THE LAST PAY DATE"
"PRESS PF6 TO DISPLAY THE NEXT PAY DATE"
COMPUTE
  SCREENINDEX/I5 = IF PFKEY IS 'PF04' THEN 0
    ELSE IF PFKEY IS 'PF05' THEN SCREENINDEX - 8
    ELSE IF PFKEY IS 'PF06' THEN SCREENINDEX + 8
    ELSE SCREENINDEX;
IF PFKEY IS 'PF04' THEN GOTO TOP ELSE GOTO DISPLAY;

Pressing one of the PF keys gives the variable PFKEY a value that the request tests to adjust SCREENINDEX. By adding eight to SCREENINDEX, the request displays the next block of records. By subtracting eight from SCREENINDEX, the request displays the previous block of records.

The Modification Phase: The GETHOLD Statement

How to:

Reference:

During the modification phase, the request retrieves records from the Scratch Pad Area and uses them to modify the data source. It retrieves records using the GETHOLD statement. The syntax is

GETHOLD

without any parameters. The GETHOLD statement retrieves the record whose index value is the value of the HOLDINDEX field. The HOLDINDEX field is then incremented by 1. For example, if the current value of HOLDINDEX is 5, the GETHOLD statement retrieves Record 5 from the Scratch Pad Area. HOLDINDEX is then increased to 6.

After the record is retrieved, all fields in the record become available for processing: matching, adding new segment instances, updating, deleting, and computations. Note that you may need to activate these fields before processing. For example, these statements update an employee's monthly pay using Record 5 in the Scratch Pad Area. Record 5 contains two fields: PAY_DATE and GROSS:

COMPUTE HOLDINDEX = 5;
GETHOLD
ACTIVATE PAY_DATE GROSS
MATCH PAY_DATE
  ON NOMATCH REJECT
  ON MATCH UPDATE GROSS

You may use the GETHOLD statement to process all the records in the Scratch Pad Area. If the records contain data loaded from different segments, use separate cases to process records from each segment. First, set the HOLDINDEX field to the index value of the first record from the segment. As the request retrieves each record, HOLDINDEX increases by 1. When HOLDINDEX is greater than the index value of the last record from the segment (which you stored earlier in a field), you can branch to another case.

For example, this request fragment updates employees' salary history and monthly pay. The Scratch Pad Area consists of the following records:

  • The first two records contain the fields DAT_INC and SALARY to update the salary history.
  • The next ten records contain the fields PAY_DATE and GROSS to update monthly pay.

The fragment is:

CASE SALSET
COMPUTE HOLDINDEX = 1;
GOTO SALUPDATE
ENDCASE
 
CASE SALUPDATE
GETHOLD
MATCH DAT_INC
  ON MATCH UPDATE SALARY
  ON MATCH    IF HOLDINDEX GT LASTSAL GOTO PAYSET
     ELSE GOTO SALUPDATE;
  ON NOMATCH REJECT
ENDCASE
 
CASE PAYSET
COMPUTE HOLDINDEX = 3;
GOTO PAYUPDATE
ENDCASE
 
CASE PAYUPDATE
GETHOLD
MATCH PAY_DATE
  ON MATCH UPDATE GROSS
  ON MATCH    IF HOLDINDEX GT LASTPAY GOTO TOP
     ELSE GOTO PAYUPDATE;
  ON NOMATCH REJECT
ENDCASE
 
DATA VIA FIDEL
END

The cases are as follows:

  • The SALSET case sets HOLDINDEX to 1, the index value of the first salary history record.
  • The SALUPDATE case updates the salary history using the records in the Scratch Pad Area. Each time the case retrieves a record, HOLDINDEX is incremented by 1. When HOLDINDEX is greater than the index value of the last salary history record (the value of field LASTSAL), the case branches to the PAYSET case.
  • The PAYSET case sets HOLDINDEX to 3, the index value of the first monthly pay record in the Scratch Pad Area.
  • The PAYUPDATE case updates monthly pay using the records in the Scratch Pad Area. When HOLDINDEX is greater than the index value of the last monthly pay record in the Area (the value of field LASTPAY), the case branches back to the top.

You can also use the GETHOLD statement to retrieve and process a single record from the Scratch Pad Area. This request fragment allows the user to delete a single monthly pay instance:

CASE DISPLAY
CRTFORM
COMPUTE LN/I1 = 0;
  "MONTHLY PAY FOR <D.FIRST_NAME <D.LAST_NAME"
  " "
  "PAY DATE           AMOUNT PAID"
  "--------           -----------"
  "1. <D.PAY_DATE(1)  <T.GROSS(1)>"
  "2. <D.PAY_DATE(2)  <T.GROSS(2)>"
  "3. <D.PAY_DATE(3)  <T.GROSS(3)>"
  "4. <D.PAY_DATE(4)  <T.GROSS(4)>"
  "5. <D.PAY_DATE(5)  <T.GROSS(5)>"
  " "
  "TO DELETE AN INSTANCE, ENTER LINE NUMBER HERE: <LN"
IF (LN LT 1) OR (LN GT 5) GOTO DISPLAY ELSE GOTO DELETE;
ENDCASE
 
CASE DELETE
COMPUTE
  HOLDINDEX = LN;
GETHOLD
MATCH PAY_DATE
  ON NOMATCH REJECT
  ON NOMATCH GOTO TOP
  ON MATCH DELETE
  ON MATCH GOTO TOP
ENDCASE

Note: Be sure that you set HOLDINDEX to a value less than or equal to the current value of the HOLDCOUNT field. A HOLDINDEX value greater than HOLDCOUNT generates an error that terminates the request.

Reference: Manual Methods: Two Examples

This section shows two examples that illustrate manual methods in multiple record processing:

  • The first example updates employees' salary history and monthly pay. This is data contained in segments on two different paths.
  • The second example deletes records of employee deductions. This is data contained in segments on one path (a parent and its child).

A diagram showing the place of salary history (SALARY), monthly pay (GROSS), and pay deductions (DED_AMT) in the EMPLOYEE data source structure appears at the beginning of The Collection Phase: The HOLDINDEX Field in this section.

Example: First Example: Processing Segments on Two Different Paths

This request is an example of a procedure that processes segments lying on different paths. The example updates employees' salary history and monthly pay. The salary history segment and monthly pay segment are both children of the employee segment, and they are on two separate paths.

This request also demonstrates the use of the GETHOLD statement to retrieve segment chains from the Scratch Pad Area. Explanatory comments are embedded in the request.

MODIFY FILE EMPLOYEE
-* First, select the parent employee instance.
 
CRTFORM
  "ENTER EMPLOYEE ID: <EMP_ID"
MATCH EMP_ID
  ON NOMATCH REJECT
  ON MATCH GOTO INITIAL
 
CASE INITIAL
-* Flush the Scratch Pad Area, then initialize fields
-* and segment chains.
 
REPEAT 1
  HOLD EMP_ID
ENDREPEAT
COMPUTE
  HOLDCOUNT/I5 = 0;
  HOLDINDEX/I5 = 1;
REPOSITION SALARY
REPOSITION PAY_DATE
GOTO SALCOLLECT
ENDCASE
CASE SALCOLLECT
-* Place the employees' salary history in the Scratch
-* Pad Area. Afterwards, store the index value of the
-* last loaded instance in the field LASTSAL. Then
-* set HOLDINDEX to 3, which is the index of the
-* first monthly pay instance.
 
NEXT SALARY
  ON NEXT HOLD DAT_INC SALARY
  ON NEXT GOTO SALCOLLECT
  ON NONEXT COMPUTE
     LASTSAL/I5 = HOLDINDEX-1;
  HOLDINDEX = 3;
  ON NONEXT GOTO PAYCOLLECT
ENDCASE
 
CASE PAYCOLLECT
-* Place the monthly pay instances in the Scratch Pad
-* Area. Afterwards, store the index value of the last
-* loaded instance in the field LASTPAY.
 
NEXT PAY_DATE
  ON NEXT HOLD PAY_DATE GROSS
  ON NEXT GOTO PAYCOLLECT
  ON NONEXT COMPUTE
     LASTPAY/I5 = HOLDINDEX-1;
  ON NONEXT GOTO DISPLAY
ENDCASE
 
CASE DISPLAY
-* If nothing was collected, go back to TOP.
-* Otherwise, display the two segment chains
-* side by side. Then reset HOLDINDEX to 1
-* to prepare for updating.
 
IF HOLDCOUNT EQ 0 GOTO TOP;
CRTFORM LINE 3
  "SALARY HISTORY AND MONTHLY PAY RECORD"
  " "
  "SALARY HISTORY               <40 MONTHLY PAY"
  --------------                <40 -----------"
  " "
  " <D.DAT_INC(1) <T.SAL(1>         <40 <D.PD(3)  <T.GROSS(3)>"
  " <D.DAT_INC(2) <T.SAL(2>         <40 <D.PD(4)  <T.GROSS(4)>"
  "                                 <40 <D.PD(5)  <T.GROSS(5)>"
  "                                 <40 <D.PD(6)  <T.GROSS(6)>"
  "                                 <40 <D.PD(7)  <T.GROSS(7)>"
  "                                 <40 <D.PD(8)  <T.GROSS(8)>"
  "                                 <40 <D.PD(9)  <T.GROSS(9)>"
  "                                 <40 <D.PD(10) <T.GROSS(10)>"
  "                                 <40 <D.PD(11) <T.GROSS(11)>"
  "                                 <40 <D.PD(12) <T.GROSS(12)>"
COMPUTE HOLDINDEX=1;
GOTO SALUPDATE
ENDCASE
 
CASE SALUPDATE
-* Update the salary history instances.
-* LASTSAL contains the index value of the
-* last salary history record.
 
GETHOLD
MATCH DAT_INC
  ON MATCH UPDATE SALARY
  ON MATCH IF HOLDINDEX GT LASTSAL GOTO HOLDSET
     ELSE GOTO SALUPDATE;
  ON NOMATCH REJECT
ENDCASE
 
CASE HOLDSET
-* Set HOLDINDEX to 3 to update the first
-* monthly pay instance.
 
COMPUTE HOLDINDEX = 3;
GOTO PAYUPDATE
ENDCASE
 
CASE PAYUPDATE
-* Update the monthly pay instances. The field
-* LASTPAY contains the index value of the last
-* monthly pay record. Afterwards, go back to TOP.
 
GETHOLD
MATCH PAY_DATE
  ON MATCH UPDATE GROSS
  ON MATCH IF HOLDINDEX GT LASTPAY GOTO TOP
     ELSE GOTO PAYUPDATE;
  ON NOMATCH REJECT
ENDCASE
 
DATA VIA FIDEL
END
Example: Second Example: Modifying Segments on the Same Path

This is a sample request that processes segments lying on the same path. The request deletes employee pay deductions. To do so, it displays a pay date on the top of the screen; below, it shows the deductions taken from the employee's pay check that date. The user can scroll back and forth between pay dates and may choose particular deductions to delete. The pay date is a field in the monthly pay segment; the deductions are fields in the child deduction segment, as shown in the diagram in The Collection Phase: The HOLDINDEX Field.

The request also demonstrates the use of the SCREENINDEX field to display different groups of records on subscripted CRTFORMs, and the use of the GETHOLD statement to retrieve specific records. Explanatory comments are embedded in the request.

MODIFY FILE EMPLOYEE
 
-* First, select the parent employee instance.
 
CRTFORM
  "ENTER EMPLOYEE ID: <EMP_ID"
MATCH EMP_ID
  ON NOMATCH REJECT
  ON MATCH GOTO INITIAL
 
CASE INITIAL
-* Flush the Scratch Pad Area, then initialize fields
-* and segment chains.
 
REPEAT 1
  HOLD EMP_ID
ENDREPEAT
COMPUTE
  HOLDCOUNT/I5    = 0;
  HOLDINDEX/I5    = 1;
  SCREENINDEX/I5  = 0;
BLOCKCOUNT/I5     = 0;
REPOSITION PAY_DATE
GOTO PAYCOLLECT
ENDCASE
CASE PAYCOLLECT
-* The next two cases create blocks of eight
-* instances within the Scratch Pad Area. Each block
-* consists of a monthly pay instance followed
-* by seven descendant instances in the
-* deduction segment. The field BLOCKCOUNT counts
-* the number of blocks in the Scratch Pad Area so far.
-* The field BLOCKNUM contains the total number of
-* blocks in the Area after all instances have
-* been loaded.
 
NEXT PAY_DATE
  ON NEXT COMPUTE
     HOLDINDEX = 8 * BLOCKCOUNT + 1;
     BLOCKCOUNT = BLOCKCOUNT + 1;
  ON NEXT ACTIVATE PAY_DATE
  ON NEXT HOLD PAY_DATE
  ON NEXT GOTO DEDCOLLECT
  ON NONEXT COMPUTE
     BLOCKNUM/I5 = BLOCKCOUNT;
  ON NONEXT GOTO DISPLAY
ENDCASE
 
CASE DEDCOLLECT
NEXT DED_CODE
  ON NEXT ACTIVATE DED_CODE DED_AMT
  ON NEXT HOLD DED_CODE DED_AMT
  ON NEXT GOTO DEDCOLLECT
  ON NONEXT GOTO PAYCOLLECT
ENDCASE
 
CASE DISPLAY
-* If nothing was collected, go back to TOP.
-* Otherwise, initialize the PFKEY and LINENO
-* fields. The EMPID field is for display
-* purposes. Then, display the current block.
-*
-* At the bottom of the screen is a menu to offer
-* users the choice of processing the records
-* of another employee, displaying the previous
-* block or displaying the next block. the field
-* PFKEY reads the PF key that the user presses
-* (see Chapter 16). The field LINENO contains the
-* line number of the deduction instance that the
-* user wants to delete.
 
IF HOLDCOUNT EQ 0 THEN GOTO TOP;
COMPUTE
  PFKEY/A4     = ' ';
  LINENO/I1    = 0;
  EMPID/A9     = EMP_ID;
CRTFORM LINE 1
  "DEDUCTION RECORD DELETION SCREEN"
  " "
  "EMPLOYEE: <D.EMPID     PAY DATE: <D.PAY_DATE(1)"
  " "
  "1. <D.DED_CODE(2) <D.DED_AMT(2)"
  "2. <D.DED_CODE(3) <D.DED_AMT(3)"
  "3. <D.DED_CODE(4) <D.DED_AMT(4)"
  "4. <D.DED_CODE(5) <D.DED_AMT(5)"
  "5. <D.DED_CODE(6) <D.DED_AMT(6)"
  "6. <D.DED_CODE(7) <D.DED_AMT(7)"
  "7. <D.DED_CODE(8) <D.DED_AMT(8)"
  " "
  "PRESS PF4 TO DISPLAY THE NEXT EMPLOYEE"
  "PRESS PF5 TO DISPLAY THE LAST PAY DATE"
  "PRESS PF6 TO DISPLAY THE NEXT PAY DATE"
  " "
  "TO DELETE A RECORD, ENTER LINE NUMBER HERE ==> <LINENO"
 
IF PFKEY IS 'PF04' THEN GOTO TOP;
IF (LINENO GE 1) AND (LINENO LE 7) THEN PERFORM DELETE;
IF (PFKEY IS 'PF05') OR (PFKEY IS 'PF06')
  THEN PERFORM ADJUST;
GOTO DISPLAY
ENDCASE
 
CASE ADJUST
-* Adjust SCREENINDEX to display another block.
-* The BACK and FORW fields perform the arithmetic
-* but also insure that SCREENINDEX stays within
-* its proper range. BLOCKNUM is the total number
-* of blocks in the Scratch Pad Area.
 
COMPUTE
  BACK/I5 = IF SCREENINDEX GT 8 THEN SCREENINDEX-8 ELSE 0;
  FORW/I5 = IF SCREENINDEX LT 8*(BLOCKNUM-1)
    THEN SCREENINDEX+8 ELSE 8*(BLOCKNUM-1);
SCREENINDEX = IF PFKEY IS 'PF05' THEN BACK ELSE FORW;
ENDCASE
 
CASE DELETE
-* Delete the deduction instance indicated by the user.
-* The first GETHOLD statement retrieves the monthly
-* pay instance from the Scratch Pad Area. The second
-* GETHOLD statement retrieves the desired deduction
-* instance. After activating the PAY_DATE and DED_CODE
-* key fields, the case locates the deduction instance
-* in the database and deletes it. Note: The record
-* in the Scratch Pad Area is NOT deleted and will
-* continue to appear on the screen.
 
COMPUTE HOLDINDEX = SCREENINDEX + 1;
GETHOLD
COMPUTE HOLDINDEX = SCREENINDEX + LINENO + 1;
GETHOLD
ACTIVATE PAY_DATE DED_CODE
MATCH PAY_DATE
  ON NOMATCH REJECT
  ON MATCH CONTINUE
MATCH DED_CODE
  ON NOMATCH TYPE "DEDUCTION RECORD NOT FOUND"
  ON NOMATCH GOTO DISPLAY
  ON MATCH DELETE
  ON MATCH TYPE "RECORD ON LINE <LINENO DELETED"
  ON MATCH GOTO DISPLAY
ENDCASE
 
DATA VIA FIDEL
END

Procedure: How to Sort the Scratch Pad Area With SORTHOLD

You can sort the contents of the Scratch Pad Area using any field or combination of fields in the Scratch Pad Area; you can then display them in any convenient order. The command uses syntax similar to the sorting specifications in the TABLE command.

The MODIFY subcommand that sorts the Scratch Pad Area is

SORTHOLD BY [HIGHEST] field1 [BY [HIGHEST] field2...]

where field1 is the primary sort field, and field2 to field8 are optional secondary sort fields.

Note:

  • The SORTHOLD statement cannot span more than one line. The default sort order is from low-to-high, but a high-to-low sort can be specified with the keyword HIGHEST. You can sort the Scratch Pad Area by up to eight fields.
  • If you sort the Scratch Pad Area before display, always sort by the data source key fields before entering a MATCH... UPDATE loop, to be sure the transactions are in sequence with the data source. Otherwise you increase execution time substantially. This procedure
    SORTHOLD BY ITEM

    performs this sort. It is issued after the records are displayed but before they are updated in the data source.

Consider the following Master File:

FILENAME=PRODUCT, SUFFIX=FOC
  SEGNAME=SEGONE, SEGTYPE=S1
   FIELD=ORDERNO,    ALIAS=ONO,    FORMAT=I4,  $
  SEGNAME=SEGTWO, SEGTYPE=S1, PARENT=SEGONE
   FIELD=ITEM,       ALIAS=ITEMNO, FORMAT=A3,  $
   FIELD=PRODUCT,    ALIAS=PRD,    FORMAT=A12, $
   FIELD=QTY,   ALIAS=QUANTITY,    FORMAT=I4S, $

The following procedure will display all of the ITEM instances for a specified ORDERNO, in order of the PRODUCT name and highest QTY sequence. The command

SORTHOLD BY PRODUCT BY QTY

performs the sort.

MODIFY FILE PRODUCT
CRTFORM LINE 1
  "ENTER ORDER NUMBER <ORDERNO"
MATCH ORDERNO
  ON NOMATCH GOTO TOP
  ON MATCH REPEAT 12
     NEXT ITEM
       ON NEXT HOLD ITEM PRODUCT QTY
       ON NONEXT GOTO SCREEN
  ENDREPEAT
GOTO SCREEN
CASE SCREEN
  IF HOLDCOUNT EQ 0 GOTO TOP;
 
  SORTHOLD BY PRODUCT BY HIGHEST QTY
 
  CRTFORM LINE 1
    "ORDER NUMBER IS <D.ORDERNO          "
  "                                      "
  " ITEM       PRODUCT          QUANTITY "
  " ----       -------          -------- "
  "<D.ITEM(1)  <D.PRODUCT(1)  <T.QTY(1)> "
  "<D.ITEM(2)  <D.PRODUCT(2)  <T.QTY(2)> "
     .
     .
     .
  "<D.ITEM(12) <D.PRODUCT(12) <T.QTY(12)>"
 
  SORTHOLD BY ITEM
  REPEAT HOLDCOUNT
    MATCH ITEM
      ON MATCH UPDATE 
QTY
      ON NOMATCH GOTO 
ENDREPEAT
  ENDREPEAT
  GOTO TOP
ENDCASE
DATA VIA FIDEL
END

Information Builders