Join tables using multiple FOR phrases
- Last Updated: March 19, 2024
- 3 minute read
- OpenEdge
- Version 12.8
- Documentation
You can use multiple record phrases to join records from more than one table:
|
The following figure shows the result.
There are several things to note about this example:
- The AVM retrieves and joins the tables in the order you specify them in,
in effect following your instructions from left to right. In this example, it starts through
the set of all
Customerswhere theStatefield= "NH". For the first record, it defines a set ofOrderswith the sameCustNumvalue (represented by theOFsyntax in this case). For each matching pair, it establishes thatCustomerrecord and itsOrderrecord and makes them available to all the rest of the statements in the block. Because there are typically multipleOrdersfor aCustomer, the result is a one-to-many join, where the sameCustomerremains current for multiple iterations through the block, one for each of itsOrders, as the output in the previous figure shows. - If you change the sequence of the tables in the statement, the AVM might
retrieve a very different set of records. For example, using the syntax
FOR EACH Order WHERE ShipDate NE ?, EACH Customer OF Order, you would get a list of everyOrderin theOrdertable with aShipDate, plus its (one) matchingCustomerrecord. Because there is just oneCustomerfor eachOrder, this would result in a one-to-one join with no repeated records. - The default join you get is called an inner
join. In matching up
Customersto theirOrders, the AVM skips anyCustomerthat has noOrderswith aShipDatebecause there is no matching pair of records. The alternative to this type of join, called an outer join, does not skip thoseCustomerswith noOrdersbut instead supplies unknown values from a dummyOrderwhen noOrdersatisfies the criteria. ABL has anOUTER-JOINkeyword, but you can use it only when you define queries of the kind you saw inDEFINE QUERYstatements, not in aFOR EACHblock. To get the same effect usingFOR EACHblocks, you can nest multiple blocks, one to retrieve and display the Customer and another to retrieve and display its Orders. You did this back in the sample procedure in Introduction to ABL. Generally this is more effective than constructing a query that might involve a one-to-many relationship anyway, because it avoids having duplicated data from the first table in the join. - You can add a
WHEREclause and/or aBYclause to each record phrase if you wish. You should always move eachWHEREclause up as close to the front of the statement as possible to minimize the number of records retrieved. For example, the statementFOR EACH Customer, EACH Order OF Customer WHERE State = "NH" AND ShipDate NE ?would yield the same result but retrieve many more records in the process. It would go through the set of allCustomers, retrieve eachOrderfor eachCustomer, and then determine whether theStatewas"NH"and theShipDatewas not unknown. This code is very inefficient. The way ABL handles data retrieval is different from SQL, where the table selection is done at the beginning of aSELECTstatement and theWHEREclause is after the list of tables. The SQL form depends on the presence of an optimizer that turns the statement into the most efficient retrieval possible. The advantage of ABL form is that you have greater control over exactly how the data is retrieved. But with this control comes the responsibility to construct yourFORstatements intelligently. - Because two records,
CustomerandOrder, are scoped to theFORblock, you might need to qualify field names that appear in both of them. If you just writeDISPLAY CustNumyou get a syntax error when you try to run the procedure, as shown in the following figure.Figure 2. Syntax error message