SQL Natural Join

This article provides an overview of the natural join in SQL, as well as some basic examples.

What is a Natural Join?

The SQL natural join is a type of equi-join that implicitly combines tables based on columns with the same name and type. The join predicate arises implicitly by comparing all columns in both tables that have the same column names in the joined tables.

The result set contains only one column for each pair of equally named columns. If no columns with the same names are found, the result will be a cross join.

Syntax

A natural join can be applied to any INNER, LEFT, RIGHT, or FULL join. You simply prefix the join type with the NATURAL keyword.

Example of the syntax used on an inner join:

SELECT *
FROM Table1 NATURAL INNER JOIN Table2 
ON Table1.Column = Table2.Column;

Seeing as INNER is the default value, you can also do it like this:

SELECT *
FROM Table1 NATURAL JOIN Table2 
ON Table1.Column = Table2.Column;

The NATURAL keyword places an implicit USING clause to the join constraints. It forms a USING list consisting of all column names that appear in both input tables. This obviously only applies to DBMSs that support the USING clause.

Not all DBMSs support natural joins, so check with your DBMS’s documentation.

As I write this, natural joins are supported in PostgreSQL, MySQL, MariaDB, SQLite, and Oracle. However, natural joins are not supported in SQL Server (2019).

Examples

Here are some examples to demonstrate.

Sample Data

First, here are the tables we’ll use for the examples.

The PetTypes table:

+-------------+-----------+
| PetTypeId   | PetType   |
|-------------+-----------|
| 1           | Bird      |
| 2           | Cat       |
| 3           | Dog       |
| 4           | Rabbit    |
+-------------+-----------+
(4 rows affected)

The Pets table:

+---------+-------------+-----------+-----------+------------+
| PetId   | PetTypeId   | OwnerId   | PetName   | DOB        |
|---------+-------------+-----------+-----------+------------|
| 1       | 2           | 3         | Fluffy    | 2020-11-20 |
| 2       | 3           | 3         | Fetch     | 2019-08-16 |
| 3       | 2           | 2         | Scratch   | 2018-10-01 |
| 4       | 3           | 3         | Wag       | 2020-03-15 |
| 5       | 1           | 1         | Tweet     | 2020-11-28 |
| 6       | 3           | 4         | Fluffy    | 2020-09-17 |
| 7       | 3           | 2         | Bark      | NULL       |
| 8       | 2           | 4         | Meow      | NULL       |
+---------+-------------+-----------+-----------+------------+
(8 rows affected)

The Owners table:

+-----------+-------------+------------+----------------+-------------------+
| OwnerId   | FirstName   | LastName   | Phone          | Email             |
|-----------+-------------+------------+----------------+-------------------|
| 1         | Homer       | Connery    | (308) 555-0100 | [email protected] |
| 2         | Bart        | Pitt       | (231) 465-3497 | [email protected]  |
| 3         | Nancy       | Simpson    | (489) 591-0408 | NULL              |
| 4         | Boris       | Trump      | (349) 611-8908 | NULL              |
| 5         | Woody       | Eastwood   | (308) 555-0112 | [email protected] |
+-----------+-------------+------------+----------------+-------------------+

Note that:

  • The PetTypeId column of the Pets table is a foreign key of the PetTypeId of the PetTypes table (which is the primary key of that table).
  • The OwnerId column of the Pets table is a foreign key of the OwnerId column of the Owners table.

Example 1 – Natural Inner Join

Here’s an example of performing a natural inner join against two of those tables.

SELECT 
    PetName,
    PetType
FROM Pets
NATURAL JOIN PetTypes;

Result:

 petname | pettype 
---------+---------
 Fluffy  | Cat
 Fetch   | Dog
 Scratch | Cat
 Wag     | Dog
 Tweet   | Bird
 Fluffy  | Dog
 Bark    | Dog
 Meow    | Cat
(8 rows)

In this example, the natural join implicitly joined the tables on the two PetTypeId columns (i.e. the Pets.PetTypeId column, and the PetTypes.PetTypeId column).

This is an implicit way of doing the following:

SELECT 
    PetName,
    PetType
FROM Pets
INNER JOIN PetTypes USING (PetTypeId);

Which actually does the following.

SELECT 
    p.PetName,
    pt.PetType
FROM Pets p
INNER JOIN PetTypes pt 
ON p.PetTypeId = pt.PetTypeId;

Example 2 – Natural Right Join

Here’s an example of performing a natural right join against two of those tables. This time we have to specify the join type, seeing as we don’t want the (default) inner join.

SELECT 
    p.PetName,
    pt.PetType
FROM Pets p
NATURAL RIGHT JOIN PetTypes pt;

Result:

 petname | pettype 
---------+---------
 Fluffy  | Cat
 Fetch   | Dog
 Scratch | Cat
 Wag     | Dog
 Tweet   | Bird
 Fluffy  | Dog
 Bark    | Dog
 Meow    | Cat
         | Rabbit
(9 rows)

In this case, it’s the same as doing the following:

SELECT 
    p.PetName,
    pt.PetType
FROM Pets p
RIGHT JOIN PetTypes pt 
ON p.PetTypeId = pt.PetTypeId;

Example 3 – Natural Full Join on 3 Tables

Here’s an example of performing a natural full join on all three tables.

SELECT 
    PetName,
    PetType,
    CONCAT(FirstName, ' ', LastName) AS PetOwner
FROM Owners NATURAL FULL JOIN Pets
NATURAL FULL JOIN PetTypes;

Result:

 petname | pettype |    petowner    
---------+---------+----------------
 Fluffy  | Cat     | Nancy Simpson
 Fetch   | Dog     | Nancy Simpson
 Scratch | Cat     | Bart Pitt
 Wag     | Dog     | Nancy Simpson
 Tweet   | Bird    | Homer Connery
 Fluffy  | Dog     | Boris Trump
 Bark    | Dog     | Bart Pitt
 Meow    | Cat     | Boris Trump
         |         | Woody Eastwood
         | Rabbit  |  
(10 rows)

This time we have a pet owner that doesn’t have a pet, as well as a pet type that’s not assigned to a pet.

Example 4 – Using the Asterisk (*) Wildcard Character

Here’s an example that uses the asterisk (*) wildcard character to select all columns.

SELECT *
FROM Pets
NATURAL JOIN PetTypes;

Result:

 pettypeid | petid | ownerid | petname |    dob     | pettype 
-----------+-------+---------+---------+------------+---------
         2 |     1 |       3 | Fluffy  | 2020-11-20 | Cat
         3 |     2 |       3 | Fetch   | 2019-08-16 | Dog
         2 |     3 |       2 | Scratch | 2018-10-01 | Cat
         3 |     4 |       3 | Wag     | 2020-03-15 | Dog
         1 |     5 |       1 | Tweet   | 2020-11-28 | Bird
         3 |     6 |       4 | Fluffy  | 2020-09-17 | Dog
         3 |     7 |       2 | Bark    |            | Dog
         2 |     8 |       4 | Meow    |            | Cat
(8 rows)

Note that the pettypeid column is only returned once, even though there are two columns with that name (one in each table). This is how natural joins deal with columns of the same name across tables.