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 thePets
table is a foreign key of thePetTypeId
of thePetTypes
table (which is the primary key of that table). - The
OwnerId
column of thePets
table is a foreign key of theOwnerId
column of theOwners
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.