Set-based Processing

In this section:

 

Maintain provides the power of set-based processing, enabling you to read, manipulate, and write groups of records at a time. You manipulate these sets of data using a data structure called a database stack.

A database stack is a simple temporary table. Generally, columns in a database stack correspond to data source fields, and rows correspond to records, or path instances, in that data source. You can also create your own "user-defined" columns.

The intersection of a row and a column is called a cell and corresponds to an individual field value. The database stack itself represents a data source path.

For example, consider the following Maintain command:

FOR ALL NEXT Emp_ID Pay_Date Ded_Amt INTO PayStack
 WHERE Employee.Emp_ID EQ SelectedEmpID;

This command retrieves Emp_ID and the other root segment fields, as well as the Pay_Date, Gross, Ded_Code, and Ded_Amt fields from the Employee data source and holds them in a database stack named PayStack. Because the command specifies FOR ALL, it retrieves all of the records at the same time; you do not need to repeat the command in a loop. Because it specifies WHERE, it retrieves only the records you need—in this case, the payment records for the currently-selected employee.

You could just as easily limit the retrieval to a sequence of data source records, such as the first six payment records that satisfy your selection condition,

FOR 6 NEXT Emp_ID Pay_Date Ded_Amt INTO PayStack
 WHERE Employee.Emp_ID EQ SelectedEmpID;

or even restrict the retrieval to employees in the MIS department earning salaries above a certain amount:

FOR ALL NEXT Emp_ID Pay_Date Ded_Amt INTO PayStack
 WHERE (Employee.Department EQ 'MIS') AND
       (Employee.Curr_Sal GT 23000);

Top of page

x
Which Processes Are Set-based?

You can use set-based processing for the following types of operations:

The following diagram illustrates how these operations function together in a procedure:

The diagram is explained in detail below:

  1. The procedure selects several records from the data source and, for each record, copies the values for fields A, B, and C into the database stack. It accomplishes this using the NEXT command.
  2. The procedure displays a Winform on the screen. The Winform shows multiple instances of fields A, B, and C; the field values shown on the screen are taken from the stack. This is accomplished using the WINFORM SHOW command.
  3. The procedure user views the Winform and enters and edits data. As the Winform responds to the user's activity, it automatically communicates with the procedure and updates the stack with the new data.
  4. The procedure user clicks a button to exit the Winform; the button accomplishes this by triggering the WINFORM CLOSE command.
  5. The procedure writes the values for fields A, B, and C from the stack to the selected records in the data source. The procedure accomplishes this using the UPDATE command.

Top of page

x
How Does Maintain Process Data in Sets?

Maintain processes data in sets using two features:


Top of page

x
Creating and Defining Database Stacks: An Overview

Maintain makes working with stacks easy by enabling you to create and define a database stack dynamically, simply by using it. For example, when you specify a particular stack as the destination stack for a data source retrieval operation, that stack is defined as including all of the fields in all of the segments referred to by the command. Consider the following NEXT command, which retrieves data from the VideoTrk data source into the stack named VideoTapeStack:

FOR ALL NEXT CustID INTO VideoTapeStack;

Because the command refers to the CustID field in the Cust segment, all of the fields in the Cust segment (from CustID through Zip) are included as columns in the stack. Every record retrieved from the data source is written as a row in the stack.



Example: Creating and Populating a Simple Database Stack

If you are working with the VideoTrk data source, and you want to create a database stack containing the ID and name of all customers whose membership expired after June 24, 1992, you could issue the following NEXT command:

FOR ALL NEXT CustID INTO CustNames WHERE ExpDate GT 920624;

The command does the following:

  1. Selects (NEXT) all VideoTrk records (FOR ALL) that satisfy the membership condition (WHERE).
  2. Copies all of the fields from the Cust segment (referenced by the CustID field) from the selected data source records into the CustNames stack (INTO).

The resulting CustNames stack looks like this (some intervening columns have been omitted to save space):

CustID

LastName

...

Zip

0925

CRUZ

...

61601

1118

WILSON

...

61601

1423

MONROE

...

61601

2282

MONROE

...

61601

4862

SPIVEY

...

61601

8771

GARCIA

...

61601

8783

GREEN

...

61601

9022

CHANG

...

61601



x
Creating a Database Stack

You create a database stack:

For example, this NEXT command creates the EmpAddress stack:

FOR ALL NEXT StreetNo INTO EmpAddress;

Top of page

x
Defining a Database Stack's Data Source Columns

When you define a database stack, you can include any field in a data source path. Maintain defines a stack's data source columns by performing the following steps:

  1. Scanning the procedure to identify all of the NEXT, MATCH, and INFER commands that use the stack as a destination and all the controls that use the stack as a source or destination.
  2. Identifying the data source fields that these commands and controls move into or out of the stack:
    • NEXT commands move the fields in the data source field list and WHERE phrase.
    • MATCH commands move the fields in the data source field list.
    • INFER commands move all the fields specified by the command.
    • Controls move all the fields specified by the control.
  3. Identifying the data source path that contains these fields.
  4. Defining the stack to include columns corresponding to all the fields in this path.

You can include any number of segments in a stack, as long as they all come from the same path. When determining a path, unique segments are interpreted as part of the parent segment. The path can extend through several data sources that have been joined together. Maintain supports joins that are defined in the Master File. For information about defining joins in the Master File, see the FOCUS Interface documentation for the types of data sources that you wish to join, and the Describing Data manual for FOCUS data sources. (Maintain can read data sources that have been joined to a host data source, but cannot write to them.)

The highest specified segment is known as the anchor and the lowest specified segment is known as the target. Maintain creates the stack with all of the segments needed to trace the path from the root segment to the target segment:



Example: Defining Data Source Columns in a Database Stack

In the following source code, a NEXT command refers to a field (Last_Name) in the EmpInfo segment of the Employee data source, and reads that data into EmpStack; another NEXT command refers to a field (Salary) in the PayInfo segment of Employee and also reads that data into EmpStack:

NEXT Last_Name INTO EmpStack;
.
.
.
FOR ALL NEXT Salary INTO EmpStack;

Based on these two NEXT commands, Maintain defines a stack named EmpStack, and defines it as having columns corresponding to all of the fields in the EmpInfo and PayInfo segments:

Emp_ID

Last_Name

...

Ed_Hrs

Dat_Inc

...

Salary

JobCode

071382660

STEVENS

...

25.00

82/01/01

...

$11,000.00

A07

071382660

STEVENS

...

25.00

81/01/01

...

$10,000.00

A07



Example: Establishing a Path Using Keys and Anchor and Target Segments

The following code populates CustMovies, a database stack that contains video rental information for a given customer. The first NEXT command identifies the customer. The second NEXT command selects a field (TransDate) from the second segment and a field (Title) from the bottom segment of a path that runs through the joined VideoTrk and Movies data sources:

NEXT CustID WHERE CustID IS '7173';
 
FOR ALL NEXT TransDate Title INTO CustMovies
 WHERE Category IS 'COMEDY';

The structure of the joined VideoTrk and Movies data sources looks like this:

In this NEXT command, the TransDat segment is the anchor and the MovInfo segment is the target. The resulting CustMovies stack contains all the fields needed to define the data source path from the root segment to the target segment:

The stack looks like this:

CustID

TransDate

MovieCode

...

Title

...

Copies

7173

91/06/18

305PAR

...

AIRPLANE

...

2

7173

91/06/30

651PAR

...

MY LIFE AS A DOG

...

3



x
Creating a Database Stack's User-defined Columns

In addition to creating database stack columns that correspond to data source fields, you can also create database stack columns that you define yourself. You can define these columns in two ways:



Example: Creating a User-defined Column

Consider a database stack named Pay that contains information from the Employee data source. If you want to create a user-defined column named Bonus and set its value to 10 percent of each employee's current salary, you could issue the COMPUTE command to create the new column, and then issue another COMPUTE to derive the value. You place the second COMPUTE within a REPEAT loop to execute it once for each row in the stack:

COMPUTE Pay.Bonus/D10.2;
REPEAT Pay.FocCount  Row/I4=1;
 COMPUTE Pay(Row).Bonus = Pay(Row).Curr_Sal * .10;
ENDREPEAT  Row=Row+1;

Top of page

x
Copying Data Into and Out of a Database Stack

You can copy data into and out of a database stack in the following ways:

You can use any of these commands to copy data by employing the command's INTO and FROM phrases. FROM specifies the command's data source (the source stack), and INTO specifies the command's data destination (the destination stack).



Example: Copying Data Between a Database Stack and a Data Source

In this NEXT command,

FOR ALL NEXT CustID INTO CustStack;

the INTO phrase copies the data (the CustID field and all of the other fields in that segment) into CustStack. The following UPDATE command,

FOR ALL UPDATE ExpDate FROM CustStack;

uses the data from CustStack to update records in the data source.


Top of page

x
Referring to Specific Stack Rows Using an Index

Each stack has an index that enables you to refer to specific rows. Consider the earlier example in which we created the CustNames stack by issuing a NEXT command to retrieve records from the VideoTrk data source:

FOR ALL NEXT CustID LastName INTO CustNames
 WHERE ExpDate GT 920624;

The first record retrieved from VideoTrk becomes the first row in the database stack, the second record becomes the second row, and so on.

CustID

LastName

...

Zip

1

0925

CRUZ

...

61601

2

1118

WILSON

...

61601

3

1423

MONROE

...

61601

4

2282

MONROE

...

61601

5

4862

SPIVEY

...

61601

6

8771

GARCIA

...

61601

7

8783

GREEN

...

61601

8

9022

CHANG

...

61601

You can refer to a row in the stack by using a subscript. The following example refers to the third row, in which CustID is 1423:

CustNames(3)

You can use any integer value as a subscript; an integer literal (such as 3), an integer field (such as TransCode), or an expression that resolves to an integer (such as TransCode + 2).

You can even refer to a specific column in a row (that is, to a specific stack cell) by using the stack name as a qualifier:

CustNames(3).LastName

If you omit the row subscript, the position defaults to the first row. For example,

CustNames.LastName

is equivalent to

CustNames(1).LastName

Maintain provides two system variables associated with each stack. These variables help you manipulate single rows and ranges of rows:

Maintain also provides a system variable that points to the current row of the active stack in a browser or grid on a form:

Formname.objectname.CurStkRowNum

For example, the number of the current row of the stack in Grid1 of Form1 is:

Form1.Grid1.CurStkRowNum

Top of page

x
Looping Through a Stack

The REPEAT command enables you to loop through a stack. You can control the process in different ways, so that you can loop according to several factors:

You can also increment counters as part of the loop.



Example: Using REPEAT to Loop Through a Stack

For example, the following REPEAT command loops through the Pay stack once for each row in the stack and increments the temporary field Row by one for each loop:

REPEAT Pay.FocCount  Row/I4=1;
 COMPUTE Pay(Row).NewSal = Pay(Row).Curr_Sal * 1.10;
ENDREPEAT  Row=Row+1;

Top of page

x
Sorting a Stack

You can sort a stack's rows using the STACK SORT command. You can sort the stack by one or more of its columns and sort each column in ascending or descending order. For example, the following STACK SORT command sorts the CustNames stack by the LastName column in ascending order (the default order):

STACK SORT CustNames BY LastName;

Top of page

x
Editing Stack Values

There are two ways in which you can edit a stack's values:

It is important to note that if you do not specify a row when you assign values to a stack, Maintain defaults to the first row. Thus if the Pay stack has 15 rows, and you issue the following command,

COMPUTE Pay.NewSal = 28000;

the first row receives the value 28000. If you issue this NEXT command,

FOR 6 NEXT NewSal INTO Pay;

the current row of Pay defaults to one, so the six new values are written to rows one to six of Pay, and any values originally in the first six rows of Pay are overwritten. If you wish to append the new values to Pay—that is, to add them as new rows 16 through 21—you would issue this NEXT command, which specifies the starting row:

FOR 6 NEXT NewSal INTO Pay(16);

If you want to discard the original contents of Pay and substitute the new values, it is best to clear the stack before writing to it using the following command:

STACK CLEAR Pay;
FOR 6 NEXT NewSal INTO Pay;

Top of page

x
The Default Database Stack: The Current Area

For most fields and variables referenced by a Maintain procedure, Maintain creates a corresponding column in the default database stack known as the Current Area.

The Current Area has only one row. The row includes values for the following:

Developer's Tip: Using stacks is a superior way to access and manipulate data source values; stacks function more intuitively than the Current Area. Using stacks instead of the Current Area to work with data source values is recommended.

For example, if you write 15 values for NewSal to the Pay stack, the values will also be written to the NewSal column in the Current Area; since the Current Area has only one row, its value will be the fifteenth (that is, the last) value written to the Pay stack.

The Current Area is the default stack for all FROM and INTO phrases in Maintain commands. If you do not specify a FROM stack, the values come from the single row in the Current Area; if you do not specify an INTO stack, the values are written to the single row of the Current Area, so that only the last value written remains.

The standard way of referring to a stack column is by qualifying it with the stack name and a period:

stackname.columnname

Because the Current Area is the default stack, you can explicitly refer to its columns without the stack name, by prefixing the column name with a period:

.columnname

Within the context of a WHERE phrase, an unqualified name refers to a data source field (in a NEXT command) or a stack column (in a COPY command). To refer to a Current Area column in a WHERE phrase, you should refer to it explicitly by qualifying it with a period. Outside of a WHERE phrase it is not necessary to prefix the name of a Current Area column with a period, as unqualified field names will default to the corresponding column in the Current Area.

For example, the following NEXT command compares Emp_ID values taken from the Employee data source with the Emp_ID value in the Current Area:

FOR ALL NEXT Emp_ID Pay_Date Ded_Code INTO PayStack
 WHERE Employee.Emp_ID EQ .Emp_ID;

If the Current Area contains columns for fields with the same field name, but that are located in different segments or data sources, you can distinguish between the columns by qualifying each with the name of the Master File and/or segment in which the field is located:

file_description_name.segment_name.column_name

If the Current Area contains columns for a user-defined field and a data source field that have the same name, you can qualify the name of the data source field column with its Master File and/or segment name; an unqualified reference will refer to the user-defined field column.


Top of page

x
Maximizing Database Stack Performance

When you use database stacks, there are several things you can do to optimize performance:


Information Builders