KayeILSQL-06-Multi-Table Joins

Contents

Based On

About Multi-Table Joins

INNER JOIN / SIMPLE JOIN

OUTER JOIN

JOINING MORE THAN TWO TABLES

SELF JOIN

CARTESIAN PRODUCT

References

Based On

Based On — Experience

The contents of this work are based on;

Based On — European Parliament as Data Model

This text on SQL is based on the EP-European Parliament as Data Model.

The European Parliament (EP) is the parliamentary institution of the European Union (EU).

The European Parliament is elected by the citizens of the European Union to represent their interests.

Its origins go back to the 1950s and the founding Treaties. Since 1979 its members have been directly elected by the citizens of the EU.

Elections are held every five years, and every EU citizen is entitled to vote, and to stand as a candidate, wherever they live in the EU. Parliament thus expresses the democratic will of the European Union's nearly 500 million citizens and it represents their interests in discussions with the other EU institutions.

Please Note:

The sources for the data, which are all freely obtainable from the European Union website, and from several leaflets of the EU institutions, are listed in the References section.

These sources are used to create the fictitious Business Narrative of the "Data Modelling and Normalization" Chapter.

We called this Business Narrative; "the Story of the European Union" which explains about the EU and EP, for purposes of Data Modeling.

The Story of the European Union is the last Chapter of Kaye is Learning SQL.

Based On — Oracle Database as RDBMS

This text on SQL is based on the Oracle Database as RDBMS — Relational Database Management System.

Although the SQL Statements used in this text, apply specifically to the Oracle Database implementation of SQL, they are generally compatible with many other RDBMS SQL implementations.

The knowledge in the following sections are based on my personal work experience, as well as on several Oracle Documentation, which are freely downloadable from Oracle websites.

You can find a list of these documents in the References.

The name of the documents may change in time.

You can refer to the Oracle Documentation if you need more detailed information on any of the topics in this text.

Any errors present, are mine.

Breath of Fresh Air

About Multi-Table Joins

So far we have selected data from only one table.

However, sometimes we might need to access information that has to be retrieved from more than one table.

For example, we might need to display Members of the Parliament who belong to a certain Political Group. We would like to see some details of the Political Group along with some details of the Members of the Parliament in our report.

Below, we see the structure of the MEPS table which holds details of the Members of the Parliament, and the POLITICAL_GROUPS table which holds details of the Political Groups.

MEPS Table

MEPS Table Structure

POLITICAL_GROUPS Table

POLITICAL_GROUPS Table Structure

As we already know, these two tables have a Foreign Key Relationship.

Below is the Creation Script for Table MEPS, and the Foreign Key Relationship between MEPS and POLITICAL_GROUPS is:

,pg_id number(10)
constraint pg_id_fk 
references POLITICAL_GROUPS(pg_id)
 

Creation Script for Table MEPS

create table MEPS
(mep_id			number(10)
    constraint mep_id_pk primary key
,first_name		varchar2(120)
,last_name		varchar2(120)
    constraint last_name_nn not null
,salary			number(9,2)
,bonus_pct		number(5,4)
,email			varchar2(240)
    constraint email_nn not null
    constraint email_unique unique
,tel			varchar2(20)
,internet		varchar2(120)
,start_date		date
,country_id		varchar2(4)
    constraint country_id_fk
    references COUNTRIES(country_id)
,pg_id number(10)
    constraint pg_id_fk 
    references POLITICAL_GROUPS(pg_id)
,pg_chair_or_cochair1	number(10)
    constraint pg_chair_cochair1_fk
    references MEPS(mep_id)
,pg_cochair2		number(10)
    constraint pg_cochair2_fk
    references MEPS(mep_id)
);

Here is the Constraints Tab of MEPS where we can see the Constraints created by the script above.

MEPS Table Constraints

The FOREIGN KEY Relationship (FOREIGN KEY Constraint) PG_ID_FK requires that;

We use Foreign Key Relationship to JOIN Tables and retrieve the Rows of our Choice.

Example

Display LAST NAME and FIRST NAME of the Members of the Parliaments, as well as their POLITICAL GROUP CODE and POLITICAL GROUP NAME.

select	m.last_name
,	m.first_name  
,	p.pg_code
,	p.pg_name
from	meps m
JOIN	political_groups p
ON	(m.pg_id=p.pg_id)
order by p.pg_code
, 	m.last_name
, 	m.first_name;

The Result Set is displayed below.

Not all rows are displayed.

Example on Multi-Table JOIN

FROM Clause

from meps m JOIN political_groups p

To join the two tables, we specified their names in the FROM Clause.

We used the JOIN Keyword.

We used the alias m for table MEPS.

We used the alias p for table POLITICAL_GROUPS.

TABLE Alias

ON Clause

ON (m.pg_id=p.pg_id)

To join the two tables, we specified a JOIN Condition in the ON Clause.

The columns used in the ON Clause are the Foreign Key Relationship columns of table MEPS and table POLITICAL_GROUPS.

These Foreign Key Relationship columns both have the same name in the two tables: pg_id

To eliminate ambiguity;

To join two tables together, we specified a single JOIN Condition / only one JOIN Condition in the ON Clause.

If we were joining three tables together, we would have specified at least two JOIN Conditions in the ON Clause.

To JOIN n tables together, we need a minimum of n-1 JOIN Conditions.

Columns in SELECT

select m.last_name , m.first_name , p.pg_code , p.pg_name

INNER JOIN / SIMPLE JOIN

Definition of INNER JOIN

An INNER JOIN which is sometimes called a SIMPLE JOIN is a join of two or more tables that RETURNS ONLY those rows that satisfy the JOIN Condition.

The previous example, where the SELECT Statement can also be seen below, is an examle of INNER JOIN / SIMPLE JOIN .

Sample SELECT for INNER JOIN

select	m.last_name
,	m.first_name  
,	p.pg_code
,	p.pg_name
from	meps m
JOIN	political_groups p
ON	(m.pg_id=p.pg_id)
order by p.pg_code
, 	m.last_name
, 	m.first_name;

Which Rows does the INNER JOIN RETURN?

The Sample SELECT Statement above returns Matching Rows of tables MEPS and POLITICAL_GROUPS based on the JOIN Condition:


FROM MEPS M 
JOIN POLITICAL_GROUPS P
ON (M.PG_ID = P.PG_ID)

ONLY "Members of the Parliament that BELONG TO a Political Group" are RETURNED.

ONLY "Political Groups that HAVE Members of the Parliament" are RETURNED.

Which Rows does the INNER JOIN NOT Return?

The Sample SELECT Statement above returns Matching Rows of tables MEPS and POLITICAL_GROUPS based on the JOIN Condition:


FROM MEPS M 
JOIN POLITICAL_GROUPS P
ON (M.PG_ID = P.PG_ID)

If a Member of the Parliament does NOT belong to a Political Group, in which case their PG_ID is NULL, then they will NOT be returned by this query.

If there is a NEW Political Group in our Database, which have NO Members yet, this Political Group will NOT be returned by the query above.

OUTER JOIN

NEED FOR OUTER JOIN - CASE 1

The query below lists the Members of the Parliaments who do NOT belong to any Political Groups.

Members who do not belong to any of the groups are known as "non-attached Members — non-inscrits (NI)".

In our database, we DO NOT ASSIGN a PG_ID to them.

They have a NULL value in their PG_ID column.

We select the "non-attached Members — non-inscrits (NI)" in our database using the following SELECT Statement:

SELECT MEP_ID, 
LAST_NAME, 
FIRST_NAME, 
COUNTRY_ID, 
PG_ID
FROM MEPS
WHERE PG_ID IS NULL
ORDER BY MEP_ID

Non-attached Members of the Parliament

Because their PG_ID is NULL, the "non-attached Members" who do not belong to a Political Group will NOT be returned by the INNER JOIN Query of the previous section.

This was the INNER JOIN Query:

select	m.last_name
,	m.first_name  
,	p.pg_code
,	p.pg_name
from	meps m
JOIN	political_groups p
ON	(m.pg_id=p.pg_id)
order by p.pg_code
, 	m.last_name
, 	m.first_name;

Remember that a NULL is NOT Equal to any other value!

A NULL is NOT Equal to any other NULL either!!

Therefore, the INNER JOIN Condition above CANNOT be satisfied.

Hence, the "non-attached Members — non-inscrits (NI)" in our database, will NOT be returned by this SELECT Statement.

There is definitely a need for another type of JOIN.

If we want to display the details of the "non-attached Members — non-inscrits (NI)" along with the other Members of the Parliament in the results of the query above, we can then use another type of JOIN called the OUTER JOIN.

NEED FOR OUTER JOIN - CASE 2

The query below lists all the Political Groups in our database, whether they have any members or not.

In fact, we have two newly formed Political Groups, that HAVE NO MEMBERS YET:

SELECT *
FROM POLITICAL_GROUPS
ORDER BY PG_ID    

The two new Political Groups which DO NOT HAVE MEMBERS YET, are displayed with the SELECT Statement above.

All Political Groups

What if we want to include the details of these new Political Groups in the results of our INNER JOIN Query seen below?

Can we see these two new Political Groups?

select	m.last_name
,	m.first_name  
,	p.pg_code
,	p.pg_name
from	meps m
JOIN	political_groups p
ON	(m.pg_id=p.pg_id)
order by p.pg_code
, 	m.last_name
, 	m.first_name;
    

It is NOT Possible to see the two new Political Groups with our INNER JOIN Condition.

This is because;

Hence, we need another type of JOIN.

This new type of JOIN which will display the new Political Groups with NO MEMBERS YET, is called the OUTER JOIN.

Definition — OUTER JOIN

An OUTER JOIN extends the result of a INNER / SIMPLE JOIN.

An OUTER JOIN returns all rows that satisfy the join condition, and also returns some or all of those rows from one table for which no rows from the other satisfy the join condition.

LEFT OUTER JOIN

The SELECT Statement below, selects details of all MEPS in the database, even though they DO NOT belong to a Political Group.

As we have seen previously, these Members are called "non-attached Members — non-inscrits (NI)", and their PG_ID column has a NULL Value.

The SELECT Statement below, is an example of a LEFT OUTER JOIN.

For all rows in table MEPS that have no matching rows in table POLITICAL_GROUPS, database returns NULL for any select list expressions containing columns of table POLITICAL_GROUPS.

For the "non-attached Members";

select	m.last_name,
m.first_name,
nvl(p.pg_code,'NI')  "PG Code",
nvl(p.pg_name,'Non-Attached Member') "PG Name"
from	meps m LEFT OUTER JOIN
political_groups p
ON	(m.pg_id=p.pg_id)
order by pg_code desc, 
m.last_name, 
m.first_name;  
    

Left Outer

Left Outer

In this query;

Here is a definition of LEFT OUTER JOIN:

***

FROM TABLE_A LEFT OUTER JOIN TABLE_B

For all rows in TABLE_A that have NO matching rows in TABLE_B, database returns NULL for any select list expressions containing columns of TABLE_B.

***

I also like the following definition for LEFT OUTER JOIN:

***

FROM TABLE_ON_THE_LEFT LEFT OUTER JOIN TABLE_ON_THE_RIGHT

In a LEFT OUTER JOIN, the TABLE_ON_THE_LEFT in the FROM Clause is OUTER JOINED to the TABLE_ON_THE_RIGHT in the FROM Clause.

This is what a LEFT OUTER JOIN is.

Table on the LEFT is OUTER JOINED to the Table on the RIGHT.

***

Left Outer

Hence, as in the first definition above;

For all rows in TABLE_ON_THE_LEFT that have NO matching rows in TABLE_ON_THE_RIGHT, database returns NULL for any select list expressions containing columns of TABLE_ON_THE_RIGHT.

The SELECT Statement below, selects details of all the Countries in the database, whether they have any Members in the European Parliament or not.

This SELECT Statement, is an example of a RIGHT OUTER JOIN.

For all rows in table COUNTRIES that have no matching rows in table MEPS, database returns NULL for any select list expressions containing columns of table MEPS.

Hence, if there are no matching rows in table MEPS which is the Table on the LEFT or the LEFT-HAND-SIDE Table in the FROM Clause, the RIGHT OUTER JOIN will return NULLS for the following columns:

select	c.country_id,
c.country_name,	
m.last_name,	
m.first_name,	
m.pg_id
from	meps m
RIGHT OUTER JOIN countries c
ON	(m.country_id=c.country_id)
order by c.country_id,	
m.last_name, 	
m.first_name; 
        

Right Outer

In this query;

Here is a definition of RIGHT OUTER JOIN:

FROM TABLE_A RIGHT OUTER JOIN TABLE_B

For all rows in TABLE_B that have NO matching rows in TABLE_A, database returns NULL for any select list expressions containing columns of TABLE_A .

I also like the following definition for RIGHT OUTER JOIN:

***

FROM TABLE_ON_THE_LEFT RIGHT OUTER JOIN TABLE_ON_THE_RIGHT

In a RIGHT OUTER JOIN, the TABLE_ON_THE_RIGHT in the FROM Clause is OUTER JOINED to the TABLE_ON_THE_LEFT in the FROM Clause.

This is what a RIGHT OUTER JOIN is.

Table on the RIGHT is OUTER JOINED to the Table on the LEFT.

***

Right Outer

Hence, as in the first definition above;

For all rows in TABLE_ON_THE_RIGHT that have NO matching rows in TABLE_ON_THE_LEFT, database returns NULL for any select list expressions containing columns of TABLE_ON_THE_LEFT.

FULL OUTER JOIN

We want to write a query which displays all of the following:

The following SELECT Statement which uses a FULL OUTER JOIN does just that.

select	m.last_name,
m.first_name,	
p.pg_id "Political Group ID",
nvl(p.pg_code,'NI')  "PG Code",	
nvl(p.pg_name,'Non-Attached Member') "PG Name"
from	meps m 
FULL OUTER JOIN
political_groups p
ON	(m.pg_id=p.pg_id)
order by p.pg_id, 
m.last_name, 
m.first_name; 
        

Full Outer

Full Outer

Here is a definition of FULL OUTER JOIN:

***

FROM TABLE_ON_THE_LEFT FULL OUTER JOIN TABLE_ON_THE_RIGHT

***

To write a query that returns;

we use a FULL OUTER JOIN.

JOINING MORE THAN TWO TABLES

COMMITTEES Table

Below we can see the contents of the COMMITTEES table.

This table holds details of the Committees of the EP.

COMM_ID column is the Primary Key of this table.

select	comm_id,	
comm_code,	
comm_type,	
comm_name
from committees 
order by comm_id;
        

committees_01

MEP_COMM_DELG_ROLES Table

We also have a table named MEP_COMM_DELG_ROLES, which holds information on;

Since the Members of the EP are very active and one MEP takes part in more than one Committee and Delegation, this table is loaded with information.

Here is the structure of this table:

mep_com_delg_role_01.jpg

Here is the ER Diagram of the European Parliament.

We came up with this ER Diagram in Chapter 2 (Data Modelling and Normalization), which is in 3rd Normal Form, i.e. 3NF.

Our ER Model our_er_model_ep_02.jpg

Below is the CREATE TABLE Command for the table MEP_COMM_DELG_ROLES.

create table	MEP_COMM_DELG_ROLES
(mep_id		number(10)
        constraint mep_comm_delg_roles_mep_id_fk  
        references MEPS(mep_id)
        constraint mep_comm_delg_roles_mep_id_nn not null
,role_id	number(10)
        constraint mep_comm_delg_roles_role_id_fk
        references ROLES(role_id)
        constraint mep_comm_delg_roles_role_id_nn not null
,comm_id	number(10)
        constraint mep_comm_delg_roles_comm_id_fk 
        references COMMITTEES(comm_id)
,delg_id	number(10)
        constraint mep_comm_delg_roles_delg_id_fk 
        references DELEGATIONS(delg_id)
,		constraint mep_comm_delg_roles_un
        unique (mep_id, role_id, comm_id, delg_id)			
);

comment on table MEP_COMM_DELG_ROLES is
'This table holds roles of MEPs in the EP Committees and EP Delegations only.
The values in the ROLE_ID Column of the table can be one of the following:
110=Chairman/Chairwoman of a Committee or a Delegation,
140=Vice Chairman/Vice Chairwoman of a Committee or a Delegation,
170=Member in a Committee or a Delegation,
180=Substitute in a Committee or in a Delegation
';
        

We can see below the Constraints of the table created by the CREATE TABLE Command.

Constraints mep_comm_delg_role_04.jpg

This table, table MEP_COMM_DELG_ROLES only holds the Primary Key Values of the following tables:

Therefore, each of the columns MEP_ID, ROLE_ID, COMM_ID, and DELG_ID of the table MEP_COMM_DELG_ROLES are Foreign Keys Referencing the Primary Keys of MEPS, ROLES, COMMITTEES, and DELEGATIONS tables respectively.

Report for the Conference of the Presidents

We are asked to create a report for the Conference of the Presidents which displays;

In order to retrieve the information requested from us, we need to access these tables:

Below we can see the query of this report and some of its output.

select	cm.comm_code	"Code",
cm.comm_name	"Name",
m.last_name||' '||m.first_name "Member of the EP"
from mep_comm_delg_roles mr
JOIN meps m
ON (mr.mep_id =m.mep_id)
JOIN committees cm
ON (mr.comm_id=cm.comm_id)
order by cm.comm_code, 
m.last_name;
        

a Report on More Than Two Tables mep_comm_delg_role_05.jpg

TO JOIN N TABLES WE NEED A MINIMUM OF N-1 JOINS

We can see the JOIN Clause of the report below:

from mep_comm_delg_roles mr
JOIN meps m
ON (mr.mep_id =m.mep_id)
JOIN committees cm
ON (mr.comm_id=cm.comm_id)  
          

To JOIN THREE TABLES, we USED TWO JOINS.

This is the MINIMUM NUMBER of JOINS NECESSARY to JOIN THREE TABLES.

TO JOIN N TABLES, WE NEED A MINIMUM OF N-1 JOINS.

SELF JOIN

A SELF JOIN is a type of join, where a table is joined onto itself.

We need to use this type of join, when all the information we need is in a Single Table, but in Different Rows of that table.

We Want to Create this Self-Join Report

We want to create the following report:

Let's say we want to create a report which displays;

The report will look like the following — not all rows are displayed.

Self-Join Report Output

Self Join Example self_join_01.jpg

Self Join Example self_join_02.jpg

In the report output displayed above, we can see that the Members of the Parliament Vito Bonsignore (in the first row), Gunnar Hökmark, and many others are in the Political Group which is headed by Joseph Daul, i.e. Joseph Daul is the Chair of these MEPS.

Likewise, Members of the Parliament Bernard Wojciechowski (in the last row), Witold Tomczak, and many others are in the Political Group which is headed by Hanne Dahl, i.e. Hanne Dahl is the Chair of these MEPS.

All the information above come from table MEPS.

Structure of table MEPS

Structure of table MEPS is as follows:

Structure of Table MEPS

We query these columns using the following SELECT Statement.

Simple Query on table MEPS

select	mep_id,	
first_name,
last_name,	
pg_chair_or_cochair1
from meps
order  by pg_chair_or_cochair1, mep_id;
    

Below are some of the output images of the SELECT Statement above. Not all rows are displayed.

Select from Table MEPS

Select from Table MEPS

Select from Table MEPS

Select from Table MEPS

The first row returned from the query has:

But we do not see the FIRST_NAME and LAST_NAME of the Chair in this row.

***

The second row returned from the query has:

But we do not see the FIRST_NAME and the LAST_NAME of the Chair in this row, either.

However, looking at the query output, we can see that the Chair of the Members in the first row and the second row is the same person; the person with PG_CHAIR_OR_COCHAIR1 = 20001.

PG_CHAIR_OR_COCHAIR1 = 20001 means that MEP_ID of the Chair = 20001.

How can we find the FIRST_NAME and the LAST_NAME of this person (MEP_ID = 20001) and print these details in the same row with the members Vito Bonsignore and Gunnar Hökmark and many others, as seen in the Report Output above?

This Chair Person is also a Member of the Parliament.

Since this person is also a Member of the Parliament, his details are in the MEPS table as details of all the other Members are.

This Chair Person has MEP_ID = 20001.

We find the row with MEP_ID=20001.

Chair 20001

This row has the values; FIRST_NAME = 'Joseph', LAST_NAME = 'Daul', and PG_CHAIR_OR_COCHAIR1 = (null).

We found the FIRST_NAME and the LAST_NAME of the Chair (MEP_ID = 20001) . We can now print these details in the same row with the members as requested in the Report.

(null) is the display value for NULL in SQL Developer preferences. Hence we know that PG_CHAIR_OR_COCHAIR1 IS NULL.

A NULL value in the PG_CHAIR_OR_COCHAIR1 column indicates that this person (Joseph Daul) does not have a Chair — which is correct!

Create the Report Manually

We can actually keep going through the algorithm in the paragraphs above, and create the Report Output above manually.

Manually ? 🤭 🤣 🤗

It would take us some time ...

🌱 🌿 🌳

But still, we can create the report requested from us.

The SELF-JOIN Method

However, there is a much more simple and definitely a quicker way than creating this report manually.

It is called a SELF-JOIN.

In a SELF-JOIN, we join a table onto itself.

In an ordinary join, we usually join the Foreign Key Column of one table, to the Primary Key Column of another table — the tables we want to retrieve information from.

In a SELF-JOIN, we join the Foreign Key Column of a table, to the Primary Key Column of the same table — because this table is the only table we can get the required information from.

In fact, there actually is a Foreign Key - Primary Key Relationship within table MEPS.

Such a table is called a Self-Referencing Table.

We can see below part of our ER Diagram with table MEPS, and the Self-Referencing Relationship.

Self Referencing Table MEPS

Below is the CREATE TABLE Statement of table MEPS.

We can see two self-referencing relationships in this DDL (Data Definition Language) Command:

create table MEPS
(mep_id	number(10)
    constraint mep_id_pk primary key
,first_name	varchar2(120)
,last_name varchar2(120)
    constraint last_name_nn not null
,salary number(9,2)
,bonus_pct number(5,4)
,email varchar2(240)
    constraint email_nn not null
    constraint email_unique unique
,tel varchar2(20)
,internet varchar2(120)
,start_date date
,country_id varchar2(4)
    constraint country_id_fk
    references COUNTRIES(country_id)
,pg_id number(10)
    constraint pg_id_fk 
    references POLITICAL_GROUPS(pg_id)
,pg_chair_or_cochair1 number(10)
    constraint pg_chair_cochair1_fk
    references MEPS(mep_id)
,pg_cochair2 number(10)
    constraint pg_cochair2_fk
    references MEPS(mep_id)
);
        

SELECT Statement for the SELF-JOIN Report

We now build up the SELECT Statement for the SELF-JOIN Report.

We go through the following steps to build up the SELECT Statement.

  1. We assume that we have two instances of table MEPS.
  2. First instance holds details of the Members of the Parliament.
  3. Second instance holds details of the Chairs and/or Co-Chairs of the Political Groups.
  4. We give each instance an ALIAS to make things clearer.
  5. Let's call the first instance mep, for Members. Alias of the first instance is mep.
  6. Let's call the second instance chair, for Chairs. Alias of the second instance is chair.
  7. Our join condition will be:
    ON (mep.pg_chair_co_chair1 = chair.mep_id)

    The Join Condition is written like above, because;

    • In table with alias mep the "ID of the Chair of a Member" is the value in column pg_chair_co_chair1.
    • This ID value ("ID of the Chair of a Member") equals to the value of the mep_id column in the table with alias chair.

Our SELECT statement which has a Self Join will be:

select mep.first_name||' '||mep.last_name "MEP Name",
chair.first_name||' '||chair.last_name "Chair Name"
from meps mep
join meps chair
on (mep.pg_chair_or_cochair1=chair.mep_id)
order by mep.pg_chair_or_cochair1, 
mep.mep_id;    
            

Self Referencing Table MEPS with Chair Names

The output of the SELECT Statement is the same as the SELF-JOIN Report.

This was an example of a SELF-JOIN with One Self-Referencing Foreign Key.

An Example with Two Self-Referencing Foreign Keys

We now have an example of a SELF-JOIN with Two Self-Referencing Foreign Keys.

We create a report where we display NOT ONLY the Chair, BUT ALSO we display both Chairs, if the Political Group has Co-Chairs.

In this case, we access the table MEPS three times:

Join Condition for this report is seen below.

from meps mep    
join meps chair1
on (mep.pg_chair_or_cochair1=chair1.mep_id)
left outer join	meps chair2
on (mep.pg_cochair2=chair2.mep_id)      

This Join Condition uses the two Two Self-Referencing Foreign Keys of the table MEPS.

MEPS Table Two Self-Referencing Foreign Keys

select mep.first_name||' '||mep.last_name "MEP Name",	
chair1.first_name||' '||chair1.last_name "Chair / Cohair 1 Name",
chair2.first_name||' '||chair2.last_name "Cohair 2 Name"
from meps mep
join meps chair1
on (mep.pg_chair_or_cochair1=chair1.mep_id)
left outer join	meps chair2
on (mep.pg_cochair2=chair2.mep_id)
order by mep.pg_chair_or_cochair1, mep.mep_id;       
                

Self Referencing with Two Chairs

Self Referencing with Two Chairs

CROSS JOIN / CARTESIAN PRODUCT

Definition of Cartesian Product

In a SELECT Statement with two tables, when a Join Condition is omitted, when there is NO Join Condition, or when the Join Condition is Invalid, the query returns all combination of rows.

All rows in the first table are joined to all rows in the second table.

The result is a Cartesian Product of two Tables.

We have learned about Cartesian Product in "Chapter 1: A Relational Approach".

The section on Cartesian Product is under "Two Theoretical Languages / Relational Algebra / Product" of "Chapter 1: A Relational Approach".

The detailed definition of Cartesian Product below, is taken from that section.

An Example on the PRODUCT Operation

For simplicity we take two tables with one column each and perform the PRODUCT Operation on them.

TABLE_1
T1_COLUMN1
A
B
C

TABLE_1 has 1 Column and 3 Rows.

TABLE_2
T2_COLUMN1
10
20

TABLE_2 has 1 Column and 2 Rows.

What will the Result of the PRODUCT Operation be?

Product Resulting Table

If we call the Resulting Table of this PRODUCT Operation, TABLE_G, then the operation can be denoted by:

TABLE_G = TABLE_1 PRODUCT TABLE_2

TABLE_G
T1_COLUMN1 T2_COLUMN1
A 10
A 20
B 10
B 20
C 10
C 20

The Resulting Table of the PRODUCT Operation on TABLE_1 and TABLE_2, which is TABLE_G, has 6 Rows and 2 Columns.

Another Example on the PRODUCT Operation

Now, let us take the STAFF and the DEPARTMENTS tables, and perform the PRODUCT operation on these two tables.

STAFF table has 5 rows and 4 columns:

STAFF
staff id name dg id program no
802 YILDIZ 400 10
804 HEYNEN 400 20
806 KANUITH 400 30
808 ZABOROWSKI 400 40
1020 OTTOVA 400 60

DEPARTMENTS table has 3 rows and 2 columns:

DEPARTMENTS
dg id dg name
200 DG Communications
400 DG Innovation and Research
600 DG Legal Service

Cartesian Product of these two tables, will produce a Result Table with 5x3=15 Rows, and 4+2=6 Columns as seen below:

TABLE_R = STAFF PRODUCT DEPARTMENTS
TABLE_R
staff id name dg id program no dg id dg name
802 YILDIZ 400 10 200 DG Communications
802 YILDIZ 400 10 400 DG Innovation and Research
802 YILDIZ 400 10 600 DG Legal Service
804 HEYNEN 400 20 200 DG Communications
804 HEYNEN 400 20 400 DG Innovation and Research
804 HEYNEN 400 20 600 DG Legal Service
806 KANUITH 400 30 200 DG Communications
806 KANUITH 400 30 400 DG Innovation and Research
806 KANUITH 400 30 600 DG Legal Service
808 ZABOROWSKI 400 40 200 DG Communications
808 ZABOROWSKI 400 40 400 DG Innovation and Research
808 ZABOROWSKI 400 40 600 DG Legal Service
1020 OTTOVA 400 60 200 DG Communications
1020 OTTOVA 400 60 400 DG Innovation and Research
1020 OTTOVA 400 60 600 DG Legal Service

Uses of Cartesian Product

We have already seen the Definition of a Cartesian Product:

Cartesian Product will generate a large number of rows.

If a Cartesian Product is formed because of an Invalid Join Condition, or because a Join Condition was omitted by mistake, then it has to be corrected.

However, a Cartesian Product of Tables can be very useful.

I always used it myself on several occasions, when I needed test data.

Although the data created by the Cartesian Product can be meaningless, the fact that we have a large sum of rows and columns makes the Result Set very useful for tests with different purposes.

Example on Cartesian Product

We will use the COMMITTEES table and the MEPS table in our Cartesian Product example.

In this example, there is NO JOIN Condition between the two tables.

Therefore a Cartesian Product is produced when we use this SELECT Statement:

SELECT  *
FROM COMMITTEES COMM
JOIN MEPS M
ON (1=1)

All rows in the COMMITTEES table are joined to all rows in the MEPS table.

Also, all columns in the COMMITTEES table and all columns in the MEPS table, are included as the columns of the Result Set.

We can see the SELECT Statements used and the output below.

SELECT COUNT(*)
FROM COMMITTEES COMM
--23

SELECT COUNT(*)
FROM MEPS M
-- 787

SELECT 23*787 FROM DUAL
-- 18101

SELECT  COUNT(*)
FROM COMMITTEES COMM
JOIN MEPS M
ON (1=1)
--18101

SELECT  *
FROM COMMITTEES COMM
JOIN MEPS M
ON (1=1)   
                

Cartesian Product

Cartesian Product

The CROSS JOIN Clause

The CROSS JOIN Clause produces a cross-product of the two tables, which is also a Cartesian Product.

Below, we can see the same example as in the Cartesian Product Example, only using the CROSS JOIN Clause this time.

SELECT  COUNT(*)
FROM COMMITTEES COMM
CROSS JOIN MEPS M
--18101

SELECT  M.*, COMM.*
FROM COMMITTEES COMM
CROSS JOIN MEPS M   
                

Cross Join

Cross Join

This resumes the Chapter Multi Table Joins.

Breath of Fresh Air

References

just me