==================================================================== Easy outer joins with 4.5Plus! ==================================================================== Product: R:BASE Version: 4.5 Plus! or Higher ==================================================================== Area: Programming Catalog: Programming in R:BASE ==================================================================== A regular join includes the rows that match between two tables. Matching rows are determined by the linking column, a column that is common to the two tables. When the tables are joined, rows that have matching data in the linking column are included in the result, other rows are ignored. An outer join includes the rows that don't have matching values. SQL 92 defines an outer join as between two tables only. You cannot have more than two tables in the FROM clause of your SELECT command to use this new syntax. If you need to join more than two tables, create your outer join using the UNION operator of SELECT as described in the article "Working with Outer Joins" in the Jan/Feb 1993 Exchange Technical Journal (Fax #682) or by using intermediate views as described below. The outer join designation is an additional option to the FROM clause of the SELECT command. SELECT...FROM lefttblview T1 LEFT OUTER JOIN righttblview T2 RIGHT FULL ON T1.column1 = T2.column2 The type of outer join (LEFT, RIGHT or FULL) goes between the table names in the FROM clause, the keyword ON precedes the linking columns. You can add an additional WHERE clause that further qualifies the rows to be selected, as well as using the GROUP BY, HAVING and ORDER BY clauses of SELECT. Left outer join --------------- Includes the matching rows between table one (T1) and table two (T2), and rows from table one that don't have a match in table two. The rows from table one that don't have a match in table two are null filled for the table two columns. Table one is the first table referenced in the FROM clause, the table on the "left". Right outer join ---------------- Includes the matching rows between table two (T2) and table one (T1), and rows in table two that don't have a match in table one. The rows in table two that don't have a match in table one are null filled for the table one columns. Table two is the second table referenced in the FROM clause, the table on the "right". The use of LEFT or RIGHT depends the order you list the tables and from which table you want the rows that don't match. For example, ... FROM table1 LEFT OUTER JOIN table2 ... includes the rows from table1 that aren't in table2 ... FROM table1 RIGHT OUTER JOIN table2 ... includes the rows from table2 that aren't in table1. ... FROM table2 RIGHT OUTER JOIN table1 ... is the same as ... FROM table1 LEFT OUTER JOIN table2 ... You can change from RIGHT to LEFT by simply changing the tables instead of changing the OUTER JOIN specification. ... FROM table2 RIGHT OUTER JOIN table1 ... does a right outer join using table1, it returns all the rows from table1 and matching rows from table2. ... FROM table1 RIGHT OUTER JOIN table2 ... does a right outer join using table2, it returns all the rows from table2 and matching rows only from table1. It is the same as ... FROM table2 LEFT OUTER JOIN table1 ... Make sure your tables are in the right order to select the desired rows. Full outer join --------------- Includes all the rows from both tables, the rows that don't match are null filled. There will be rows with data from both tables, rows with data from table one and null for the table two columns and rows with data from table two and null for the columns from table one. This gives the same result as the R:BASE UNION command, but when used in a view, a permanent table and its corresponding data is not created in the database. An advantage with this new syntax over creating an outer join using the UNION operator with SELECT is you don't get "unnamed" columns in the result. You won't need to remember to define column names when you create your view. The syntax limits you to creating an outer join using only two tables at a time. Create a three table join by creating a view with one two-table outer join, then using that view in a second outer join. You need to be sure that the linking column for the second join is not on the outer join side of the first join, i.e. it is not null filled. For example, to link the transmaster, customer and employee tables from the Concomp sample database, first create a view joining transmaster and employee using a left outer join. This includes rows in the transmaster table that are not in the employee table. We can't include rows from employee that are not in transmaster because that fills the linking column between transmaster and customer, custid, with nulls. CREATE VIEW view1 AS SELECT T1.transid, T1.transdate, T1.invoicetotal, T1.custid, T1.empid, T2.empfname, T2.emplname FROM transmaster T1 LEFT OUTER JOIN employee T2 ON T1.empid = T2.empid This is what the data created by the view looks like. Notice the one row found by the outer join part of the definition -- a row in the transmaster table that does not have a matching row in the employee table. transid transdat invoicetotal custid empid empfname emplname ----- -------- --------------- ---- ---- -------- ------------ 4760 01/03/89 $29,457.00 100 133 Peter Coffin 4780 01/09/89 $10,364.50 105 160 Mary Simpson 4790 01/10/89 $68,733.00 104 129 Ernest Hernandez 4795 01/12/89 $192,016.00 101 102 June Wilson 4800 02/23/89 $182,469.75 105 160 Mary Simpson 4865 02/23/89 $31,775.37 102 129 Ernest Hernandez 4970 02/24/89 $166,104.75 103 131 John Smith 4975 02/27/89 $95,462.50 101 102 June Wilson 4980 02/28/89 $24,547.50 101 102 June Wilson 5000 03/01/89 $31,639.00 101 102 June Wilson 5010 03/03/89 $118,646.25 107 131 John Smith 5015 03/06/89 $45,822.00 103 131 John Smith 5050 03/07/89 $61,368.75 104 129 Ernest Hernandez 5060 03/08/89 $32,730.00 101 102 June Wilson 5065 03/14/89 $153,067.30 106 160 Mary Simpson 5070 03/15/89 $104,190.50 104 129 Ernest Hernandez 5075 03/16/89 $169,650.50 102 129 Ernest Hernandez 5080 03/20/89 $87,280.00 100 133 Peter Coffin 5085 03/19/89 $81,006.75 107 131 John Smith 5073 03/12/89 $13,921.16 101 152 -0- -0- This view returns all the rows that are in both transmaster and employee, and the rows in transmaster that do not have a matching employee id number, i.e. are not in employee. It is important to structure the outer join this way. You do not include rows from employee that aren't in transmaster, that would return NULLS for the custid column in transmaster, the column that is used to link with the customer table. Then, create the second view. This view will join the data selected by the first view with the data from the customer table. In our final result, we want customer rows that don't have a matching transaction and any of the transaction records that don't have a matching customer -- we use a full outer join. We didn't use a full outer join in the first view because we wanted to be sure that the custid column, our link to the customer table, always contains a value. CREATE VIEW view2 AS SELECT T1.*, T2.* FROM view1 T1 FULL OUTER JOIN customer T2 ON T1.custid = T2.custid. This is the data that results from this second view. It combines all the rows from the first view joining transmaster and employee with rows from the customer table. transid transdat empid empfnam emplname cus company ------- -------- --- ----- ------- -------- --- ---------------- --- -0- -0- ... -0- -0- -0- 110 Southwest Comput ... 4760 01/03/89 ... 133 Peter Coffin 100 PC Distribution ... 4780 01/09/89 ... 160 Mary Simpson 105 PC Consultation ... 4790 01/10/89 ... 129 Ernest Hernandez 104 Industrial Conce ... 4795 01/12/89 ... 102 June Wilson 101 Computer Distrib ... 4800 02/23/89 ... 160 Mary Simpson 105 PC Consultation ... 4865 02/23/89 ... 129 Ernest Hernandez 102 Industrial Compu ... 4970 02/24/89 ... 131 John Smith 103 Computer Mountai ... 4975 02/27/89 ... 102 June Wilson 101 Computer Distrib ... 4980 02/28/89 ... 102 June Wilson 101 Computer Distrib ... 5000 03/01/89 ... 102 June Wilson 101 Computer Distrib ... 5010 03/03/89 ... 131 John Smith 107 Midtown Computer ... 5015 03/06/89 ... 131 John Smith 103 Computer Mountai ... 5050 03/07/89 ... 129 Ernest Hernandez 104 Industrial Conce ... 5060 03/08/89 ... 102 June Wilson 101 Computer Distrib ... 5065 03/14/89 ... 160 Mary Simpson 106 Computer Warehou ... 5070 03/15/89 ... 129 Ernest Hernandez 104 Industrial Conce ... 5075 03/16/89 ... 129 Ernest Hernandez 102 Industrial Compu ... 5080 03/20/89 ... 133 Peter Coffin 100 PC Distribution ... 5085 03/19/89 ... 131 John Smith 107 Midtown Computer ... 5073 03/12/89 ... 152 -0- -0- 101 Computer Distrib ... This view includes all the rows from the first view, view1, the outer join between transmaster and employee, that have matching customer information, the rows from the customer table that have no transactions, and the rows from view1 that have no customer information. This example illustrates a technique you can use to do outer joins with more than two tables. When doing this, be sure to place the tables in the correct order to get the correct results. Be sure you do not structure your outer joins in such a way as to end up with nulls in a column that must be used to link with other tables. The two table outer join view can easily be used in other selects and other views to join with other tables. R:BASE Exchange Technical Journal ================================= This technical information comes from Microrim's award winning technical journal, the R:BASE Exchange. The R:BASE Exchange provides R:BASE users with usage tips, programming techniques and solutions to common problems - information that can help you get even more out of R:BASE. Available on a yearly subscription basis, or free with Premium Support. For more information, call 1-800-628-6990.