ddlRelate() Examples
First, let's review the steps to obtain a report. They are
ISOLATE
- Select the records of
interest.
ARRANGE - Arrange
them in the order needed for the report that you have in mind.
REPORT -
The input is the result of the arranging step and the output is the report. The
report will have whatever display that you specify.
If your isolation involves only one table, you do not need RELATE for the
arranging step; SORT will do the job.
When the isolation involves more than one table, RELATE is used for the
arranging step.
Inter-file relationships can be quite interesting and are best seen through
examples. We will use some of the tables in the EXAMPLE database to illustrate
relationships between tables. Even though the examples are specific, keep in
mind that the relationships shown are generic and can be found in any database.
Here are tables that will be working with:
CUSTOMERS STATES SALES INVENTORY
----------- ------ ----- -----------
cust # state store # item #
name stname item # description
street cust # type
city pdate mbcode
state yr quan_on_hand
zip mo unit_cost
age dy order_cost
discount descr reoder_point
status quan_bot
hair_color price
handed
Table Relationships
Records in different tables relate to each other in one of the following ways:
> one-to-one
> one-to-many
> many-to-one
> translations
> no relationship
One-to-one, one-to-many, many-to-one
Whenever two tables share a common field they relate to each other in one or
more of these three ways.
Look at CUSTOMERS and SALES. The common field is CUST#. A specific customer
makes many purchases in a given time period, so you expect that for each
customer record there are many sales records that "belong" to it.
These records all have the same value in the CUST# field.
Another example is INVENTORY and SALES. The common field is ITEM#. For a given
inventory record, you expect many sales records to "belong" to it.
All of these records would have the same value in the ITEM# field.
Suppose you want to produce invoices for June. The isolation step is
> CLEAR A
> FIND A SALES WHERE MO = 06
> MATCH A SALES THRU CUST# WITH CUSTOMERS
CLEAR ensure that the collection is cleared of any residue left over from
previous operations. FIND selects the June sales records, and the MATCH selects
the customer records that go with those sales. These are the records that we
want to work with, so the isolation step is complete.
Now the idea is to merge this data into one ordered file for the purpose of
reporting.
Since invoices are on a per customer basis, it is the one-to-many relationship
that we are after.
> RELATE A CUSTOMERS SALES OVER CUST# PDATE
The result of this arrangement is what the REPORT command sees when it produces
the invoices. That is a file with the following order:
CUSTOMERS
SALES
SALES
SALES
CUSTOMERS
SALES
SALES
SALES
CUSTOMERS
SALES
-
-
Each CUSTOMERS record is followed by the SALES records that belong to that
customer. The command to process this file and produce the invoices might be
> RPR A NAME DESCR PDATE
> RPR/R A NAME DESCR PDATE
> PRINT A NAME DESCR PDATE
> PRINT A NAME DESCR PDATE EVERY CUST# SPACE 1
> PRINT/M A NAME DESCR PDATE
Guidelines For RELATE
In the RELATE command you supply a list of table names and a list of field
names. The list of table names is the context (what to combine) and the list of
field names is the rule (how they are to be combined).
The order in which the names appear in these two lists determines the results.
For example, any time you have a one-to-many relationship there is the converse
many-to-one relationship:
> RELATE A SALES CUSTOMERS OVER PDATE CUST#
This produces a different file that is useful for some other report (perhaps a
report that shows daily activity patterns of your customers) but not useful for
invoices.
RELATE is a command that you have to play with for a while at first, but it
won't take too long for you to see what it can do for you. When you are
experimenting, you will observe that not all the relationships that can be
produced are useful.
Here are two guidelines to help you:
1. Think of the report that you are after from the top down and list the table
names in that order. In our invoices example it was the customers one-to-many
relationship that we were after, so the context was CUSTOMERS SALES.
2. Follow the order of the table names when supplying the field names. For
example in the RELATE just above, since SALES came first in the context, PDATE
(which is a field known only to SALES) came first in the rule. This guideline
is especially true for global field names (such as CUST#).
More examples of this in the many-to-many cases are discussed further below.
TRANSLATIONS
Another way to view the relationship when two tables share a common field is as
a translation. For example, look at CUSTOMERS and STATES.
We could form one-to-many or many-to-one hierarchies just as we did for
CUSTOMERS and SALES and get several useful reports. Instead, lets see STATES
used as a translation. Suppose that a two character state code won't do. The
isolation step would be
> CLEAR A
> FIND A SALES WHERE MO= 06
> MATCH A SALES THRU CUST# WITH CUSTOMERS
> MATCH A CUSTOMERS THRU STATE WITH STATES
The collection was cleared of any residue, the June sales records were
selected, followed by the customers who made those purchases, followed by the
state records that go with those customers.
All of the records needed for the production of invoices have now been selected
so the isolation step is complete. The arranging step would be
> RELATE A CUSTOMERS (STATES THRU STATE)
> SALES OVER CUST# PDATE
The translation appears in the syntax as a parenthetical insertion following a
table name. This translation says, in effect: " every time a CUSTOMERS
record is read follow it immediately with the appropriate STATES record."
The results file looks like
CUSTOMERS
STATES
SALES
SALES
SALES
CUSTOMERS
STATES
SALES
SALES
-
-
And the report that processes this file and produces the invoices has access to
the full state name each time it needs it.
Translations may be specifies for each or any table name specified as the
context of a RELATE. Translations always show up as parenthetical insertions
with the form
... tablename (tablename THRU fieldname) ...
Translations can be nested. To illustrate this we have to introduce a new table
that is not in our EXAMPLE database, so you cannot do this one as you read
about it.
Suppose that for some reason there is a requirement to categorize STATES as to
whether they went Republican or Democrat in the last election.
Suppose further that this information is to be displayed in our invoices
report. The database is modified as follows:
STATES PARTIES
------ -------
State party
stname partyname
The STATES table had been modified to add a third field. This new field is an
X(1) field and contains the value R or D. The new table PARTIES has only two
data records in it and is used to supply the full party name for those reports
that require it.
(Editor's note:) We are really stretching for the sake of this example. You
would have to be a real fanatic about saving storage space in order to design a
database this way. Since there are only 51 STATES records it would have been
easier all the way around to have just made the STATES table look like.
STATES
------
state
stname
partyname
But then we wouldn't have had a translation within a translation within a
translation to demonstrate. The need for it does arise in other real-world
databases.
The isolation step becomes
> CLEAR A
> FIND A SALES WHERE MO = 06
> MATCH A SALES THRU CUST # WITH CUSTOMERS
> MATCH A CUSTOMERS THRU STATE WITH STATE
> MATCH A STATES THRU PARTY WITH PARTIES
And the arranging step becomes
> RELATE A CUSTOMER -
> (STATES THRU STATE (PARTIES THRU PARTY)) -
> SALES OVER CUST # PDATE
The results would be
CUSTOMERS
STATES
PARTIES
SALES
SALES
SALES
CUSTOMERS
STATES
PARTIES
SALES
SALES
-
-
We see a translation within a translation accomplished by a parenthetical
insertion within a parenthetical insertion.
There can be more than one translation at the same level. For example, if the
PARTIES were associated with CUSTOMERS rather than with STATES the situation
would have been
CUSTOMERS STATES PARTIES
--------- ------ -------
CUST# STATE PARTY
- STNAME PARTYNAME
-
STATE
-
PARTY
-
-
And the RELATE to produce the same results as shown above would have been
> RELATE A CUSTOMERS (STATES THRU STATE) -
> (PARTIES THRU PARTY) SALES OVER CUST# PDATE
Note that this time translate clauses follow each other and that there are no
nested parentheses in the syntax.
Many-to-many
A many-to-many relationship can be recognized by looking for the following
pattern:
TABLE1 TABLE2 TABLE3
--- --- ---
FIELD1 FIELD1 FIELD2
- FIELD2 -
- - -
- - -
In our EXAMPLE database one of the occurrences of this pattern is inCUSTOMERS SALES INVENTORY
--------- ------ ---------
CUST# ITEM# ITEM#
- CUST# -
- - -
- - -
There IS A MANY-TO-MANY RELATIONSHIP BETWEEN customers and INVENTORY. At first you may think that there is no relationship at all because these two do not share a common field. But there is another table, SALES, where information from these two comes together.
This third table represents data that was captured when a real event took place (a customer making a purchase).
This kind of relationship abounds in the real world. Consider EMPLOYEES and PROJECTS.EMPLOYEES PROJECTS
--------- --------
empl_no proj_no
empl_name proj_name
And the third table that describes the event that brings these two together might be TIME_CARDS.TIME_CARDS
----------
empl_no
proj_no
work_data
hours
rate
When an employee spends time on a project the event is captured in a data record that identifies which employee, which project, how many hours were worked, the data, and the rate per hour for this employee.
Another might be SHIPS and PORTS:SHIPS PORTS
----- -----
ship # port#
ship_name port_name
- -
- -
And event that establishes the many-to-many relationship between these two occurs each time a ship visits a port.VISITS
------
SHIP
PORT
VISIT_DATA
BBL_LOADED
PBB1
Here we assumed that it was an oil tanker and the event was "On such-and-such date ship so-and-so visited port thus-and-so and loaded so many barrels at this price per barrel."
As we look at CUSTOMERS SALES and INVENTORY remember that the example is generic.
Suppose we want an internal report that is very much like the invoice report except that we want to show cost information associated with each sales record and with the total invoice. Suppose further that we require the full state name in our report. The isolation step might be
> CLEAR A
> FIND A WHERE STATUS = OK
> MATCH A CUSTOMERS THRU CUST # WITH SALES
> MATCH A SALES THRU ITEM# WITH INVENTORY
> MATCH A CUSTOMERS THRU STATE WITH STATES
We find a particular subset of customers, the sales records that go with that set of customers, and the states records that go with that set of customers. Finally, since we need cost information associated with each sales record, we select the inventory records that go with those sales.
> RELATE A CUSTOMERS (STATE THRU STATE)-
> INVENTORY SALES OVER CUST# ITEM#
This is still an invoice-type report and is still on a per-customer basis, so CUSTOMERS is still on top. But instead of grouping the sales under the customers, we want them grouped under inventory so we can include the cost information associated with each sales.
Following Guideline 1, the context is CUSTOMERS INVENTORY SALES.
Following Guideline 2, the rule is CUST# ITEM#. The result isCUSTOMERS
STATES
INVENTORY
SALES
SALES
SALES
INVENTORY
SALES
SALES
CUSTOMERS
STATES
INVENTORY
SALES
SALES
INVENTORY
SALES
-
-
For each customer record the sales records are grouped under the appropriate inventory record so the cost information is available to the report when it is needed.
Finally, the REPORT command to get our record might be
> REPORT A ACCORDING TO C_INVOICE
If you are trying these examples as you read about them, the report definition C_INVOICE does exist. Also, you can use the RAWPRINT command to examine the results file created by the RELATE command.
Try
> RPR A NAME STNAME UNIT_COST DESCR QUAN_BOTThe other side of many-to-many:
We have seen one side of a many-to-many relationship, the side with CUSTOMERS on top. Here we saw many INVENTORY records associated with a given CUSTOMERS record. How about the side with INVENTORY on top? Here we see many CUSTOMERS records associated with a given INVENTORY record.
Suppose we want to profile the profit performance of a particular inventory item. The isolation step is
> CLEAR A
> FIND A WHERE DESCRIPTION = BOOZE
> MATCH A INVENTORY THRU ITEM# WITH SALES
> MATCH A SALES THRU CUST# WITH CUSTOMERSThis report is to be on a per-inventory basis, so INVENTORY is on top. We need to group the sales under the appropriate customers records so that the discount information is available. So, following Guideline 1, our context is INVENTORY CUSTOMERS SALES. And, following Guideline 2, our rule includes ITEM# CUST# stated in that order.
ITEM# and CUST# are the global fields and follow the spirit of Guideline 2 exactly. PDATE is a local field known at the lowest level of detail (SALES). For fields like this we can vary the breakouts we get by how they are placed in the rule. We can take liberties with Guideline 2 when we are dealing with local fields at the lowest level of detail. For this report we want it first.
> RELATE A INVENTORY CUSTOMERS -
> SALES OVER PDATE ITEM# CUST#
The results file is indicated below. But without the PDATE variation to Guideline 2 we could not have made the comment shown below. After you have viewed the suggested report, try the RELATE and PDATE last in the rule and see the difference in the results file. You get a file useful for some other report.INVENTORY
CUSTOMERS
SALES
SALES
SALES
CUSTOMERS
SALES
-
-
All January detail occurs before February, etc., so the report can get monthly breakouts.
Finally, the report we are after can be viewed with
> REPORT A ACCORDING TO RFRPT
There is a whole series of profile reports available in the EXAMPLE database. You can get at them via the PROFILES Menu. Don't forget that you can view the content of any Procedure or Report definition by using the List command.
PRESENT BY
The PRESENT BY part of the RELATE command syntax is used to control the primary order of presentation for any report. For an example, lets look again at the first invoice report that we achieved earlier. It was
>CLEAR A
>FIND A SALES WHERRE MO = 06
>MATCH A SALES THRU CUST # WITH CUSTOMERS
>RELATE A CUSTOMERS SALES OVER CUST # PDATE
>REPORT A ACCORDING TO P_INV
The question is: When you are presented with the whole stack of invoices, what order do they have as you are flipping through the pages? The answer is: The pages occur in CUST# order since that is the way that this RELATE left them. What if you want this same report but you want the pages to come in alphabetical order by customer name?
>RELATE A CUSTOMERS SALES OVER CUST# PDATE -
>PRESENT BY NAME
First the hierarchies needed for the report are formed, and then they are rearranged according to the PRESENT BY criterion.
PRESENT BY is always last in the RELATE syntax, and it too is a list of field names. We don't need guidelines for these since they simply act as a final sort. Do note, however, that a field name in the PRESENT BY list cannot come from the detail table(s).
For example, in this case it must be something that occurs only per package of information for a customer, NAME satisfies that requirement.
To see more discussion and example of RELATE, see the STEPS Menu in the EXAMPLE database. STEPS can be found on the DESCRIPTIONS Menu.
Copyright © 2019 , WhamTech, Inc. All rights reserved. This
document is provided for information purposes only and the contents hereof are
subject to change without notice. Names may be
trademarks of their respective owners.