794.TXT ===================================================================== Creating a Many-to-Many Report ===================================================================== PRODUCT: R:BASE VERSION: 4.5++ or Higher ===================================================================== CATALOG: Forms, Reports & Labels AREA : REPORTS ===================================================================== A relational database depends on storing descriptive information in separate tables and then relating those tables together to display all the relevant data. The relationship between tables is vital. A relationship is defined by linking columns, which are columns that are from different tables and contain matching data. Linking columns often have the same name in both tables. There are three basic relationships between tables in a relational database: One-to-one_there is only one row in each table where the linking column(s) contain matching data. The linking column in each table is unique. When two tables with a one-to-one relationship are joined, the result is a "one" table. One-to-many_in one of the tables, the linking column is unique, there is only one row for each value. In the other table, there can be one row or many rows for the linking column. When the tables are joined, the result is a "many" table. The number of rows returned is the number of rows from the "many" table. Many-to-many_in both tables, there can be many rows for the linking column(s). The linking column value is not unique in either table. The result of a join between two "many" tables is a "many" table. The number of rows returned is the number of rows in one table multiplied by the number of rows in the other table. Relationships are usually defined between two tables at a time. Relationships between more than two tables are more easily defined when taken two at a time. For example, a one-to-many-to-many join is really a one-to-many join and a many-to-many join. The one-to-many is the most common relationship in a relational database. For example, the relationship between customers and orders is a one-to-many relationship. Each customer has a row of data in a customer table, but can have many associated rows in an orders table. An example of a many-to-many relationship is the relationship between orders and payments. An order can have many payments associated with it, and a payment can be associated with many orders. When orders and payments are connected to customers, the relationship becomes a one-to-many-to-many. Each customer has a row of data in a customer table, many associated rows in an orders table, and many associated rows in a payments table. The payments and orders are both associated to the customer, but not necessarily to each other. Reports are easy to create on one-to-one or one-to-many relationships. It is difficult to create a report on tables with a many-to-many or one-to-many-to-many relationship. The desired report layout is often one with multiple types of detail information associated with one identifying record. For example: header information about the customer - the "one" table all the order data - from a "many" table sub-total of orders all the payment - from the other "many" table sub-total of payments footer information for the customer - total of orders and payments header information about the customer - the "one" table all the order data - from a "many" table sub-total of orders all the payment - from the other "many" table sub-total of payments footer information for the customer - total of orders and payments etc. This layout is very difficult to achieve. It is essentially a report with two different detail sections having different data layouts for each section. The R:BASE report writer can't do this. You can get creative with views or manipulate the data and store it in a temporary table to get close to this type of a report. But, with the addition of PAGEMODE in R:BASE 4.5++, this type of report is easy to create using the R:BASE programming language. You have complete control over the order of the data and how it is displayed. Following is an example of a PAGEMODE report printing both order and payment information for customers. Sample page of report output: 204 Electronic City 123 College Way Amherst, MA 01002 Order# PO# Order Date Order Amount Sold By ------ ------ ---------- ------------ ---------- - H002 2022 07/24/94 $7,110.00 Malone H010 2056 08/28/94 $3,510.00 Malone ------------ $10,620.00 Payment Date Order# Payment Amount ------------ ------ -------------- 09/15/94 H010 $1,755.00 09/15/94 H002 $6,740.00 10/10/94 H010 $1,755.00 ------------- $10,250.00 Balance Due: $370.00 *(MANY.CMD - Report with two detail sections ) CON hifi CLS SET HEADING OFF SET PAGEMODE OFF SET LINES 40 SET MESSAGE OFF SET VAR vstoreid INT, vrow INT DECLARE c1 CURSOR FOR SELECT StoreID, StoreName, Address, + (City + ',' & State & Zipcode) FROM storelist DECLARE c2 CURSOR FOR SELECT OrderNumber, EmployeeID, PONumber, + OrderDate, TotalSale FROM orders WHERE StoreID = .vstoreid+ ORDER BY OrderDate DECLARE c3 CURSOR FOR SELECT OrderNumber, PayAmount, PayDate+ FROM payments WHERE StoreID = .vstoreid ORDER BY PayDate SET PAGEMODE ON OPEN c1 FETCH c1 INTO vstoreid vi1, vcompany vi2, vaddress vi3, + vcitystzip vi4 OUTPUT many.out WHILE SQLCODE <> 100 THEN WRITE .vstoreid=4 AT 3,3 WRITE .vcompany AT 3,9 WRITE .vaddress AT 4,9 WRITE .vcitystzip AT 5,9 WRITE 'Order# PO# Order Date Order Amount Sold By ' + AT 7 3 WRITE '------ ------ ---------- ------------ + -----------' +AT 8,3 SET VAR vrow = 9 OPEN c2 RESET FETCH c2 INTO vOrder# i1, vEmpiD i2, vPONum i3, vOrderDate i4, + vTotalSale i5 WHILE SQLCODE <> 100 THEN SET VAR vname = LastName IN salespeople WHERE employeeid=.vempid WRITE .vorder# AT .vrow,4 WRITE .vponum AT .vrow,13 WRITE .vorderdate AT .vrow,23 WRITE .vtotalsale AT .vrow,36 USING '$999,999.00' WRITE .vname AT .vrow, 54 SET VAR vrow = (.vrow + 1) FETCH c2 INTO vOrder# i1,vEmpiD i2, vPONum i3,vOrderDate i4, + vTotalSale i5 ENDWH SELECT SUM(totalsale) INTO vtotal FROM orders WHERE + storeid=.vstoreid SET VAR vrow = (.vrow + 1) WRITE '------------' AT .vrow,36 SET VAR vrow = (.vrow + 1) WRITE .vtotal AT .vrow,36 USING '$999,999.00' SET VAR vrow = (.vrow + 2) WRITE 'Payment Date Order# Payment Amount ' + AT .vrow,8 SET VAR vrow = (.vrow + 1) WRITE '------------ ------ --------------' AT .vrow ,8 SET VAR vrow = (.vrow + 1) OPEN c3 RESET FETCH c3 INTO vOrderNumber i1, vpayamount i2, vpaydate i3 WHILE sqlcode <> 100 THEN WRITE .vpaydate AT .vrow,9 WRITE .vordernumber AT .vrow,25 WRITE .vpayamount AT .vrow,36 USING '$999,999.00' SET VAR vrow = (.vrow + 1) FETCH c3 INTO vOrderNumber i1, vpayamount i2, vpaydate i3 ENDWH SET VAR vrow = (.vrow + 1) SEL SUM(payamount) INTO vtotalpaid FROM payments WHERE + storeid=.vstoreid IF vtotalpaid <> 0 THEN WRITE '-------------' AT .vrow,36 SET VAR vrow = (.vrow + 1) WRITE .vtotalpaid AT .vrow,36 USING '$999,999.00' ENDIF SET VAR vbalance = (.vtotal - .vtotalpaid) SET VAR vrow = (.vrow + 2) WRITE 'Balance Due:' AT .vrow ,24 WRITE .vbalance AT .vrow,36 USING '$999,999.00' NEWP SET VAR vrow = 9 FETCH c1 INTO vstoreid vi1, vcompany vi2, vaddress vi3, + vcitystzip vi4 ENDWH OUTPUT SCREEN SET PAGEMODE OFF SET HEADINGS ON SET LINES 20 SET MESSAGE ON TYPE many.out Setup the report environment. Initialize variables. Declare the cursors to retrieve the data. The storelist table is the "one" table, the orders and payments tables are the "many" tables. The cursors are related, only data associated with the corresponding row in the storelist table is retrieved Get the first row of customer data and write the heading. The heading for the orders data Get the detail information for orders. Write the detail data for orders. Calculate and display the total order amount for the customer. The heading for the payments data. Get the detail information for payments. Write the detail data for payments. Note that although the amounts line up with the orders detail, the other data is formatted differently. Calculate and display the total payment amount for the customer. Calculate and display the total balance amount for the customer. Send the page and fetch the next customer. Close the report and reset the environment.