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);
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:
Maintain processes data in sets using two features:
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.
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:
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 |
You create a database stack:
Winforms are introduced in Winforms and Event-driven Processing; the Winform Painter used to design and create Winforms is described in Using the Winform Painter.
For example, this NEXT command creates the EmpAddress stack:
FOR ALL NEXT StreetNo INTO EmpAddress;
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:
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:
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 |
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 |
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:
Because all Maintain variables are local to a procedure, you must redefine variables in each procedure in which you use them. For user-defined stack columns, you accomplish this by simply reissuing the original COMPUTE command in each procedure to which you are passing the stack. (You only need to specify the variable's format; do not specify its value, which is passed with the stack.)
Unlike other kinds of stack columns, you cannot update a virtual column or field, and you cannot test it in a WHERE phrase.
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;
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).
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.
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:
IF CustNames.FocCount EQ 0 THEN PERFORM NoData;
IF Rental.FocIndex LT Rental.FocCount THEN COMPUTE Rental.FocIndex = Rental.FocIndex + 1;
You can then invoke a second function that uses FocIndex to retrieve desired records into the MovieList stack:
FOR ALL NEXT CustID MovieCode INTO MovieList WHERE VideoTrk.CustID EQ Rental(Rental.FocIndex).CustID;
The syntax
stackname(stackname.FocIndex)
is identical to
stackname()
so you can code the previous WHERE phrase more simply as follows:
WHERE VideoTrk.CustID EQ Rental().CustID
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
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.
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;
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;
There are two ways in which you can edit a stack's values:
COMPUTE Pay(7).NewSal = 35000;
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;
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.
When you use database stacks, there are several things you can do to optimize performance:
Information Builders |