PostgreSQL Same Table Left Outer Join With Multiple Tables
Categories:
PostgreSQL Same Table Left Outer Join With Multiple Tables

Learn how to perform a LEFT OUTER JOIN on a single PostgreSQL table with itself, effectively querying hierarchical or related data within the same dataset using multiple aliases.
Performing a LEFT OUTER JOIN
on a single table with itself, often referred to as a self-join, is a powerful technique in PostgreSQL. This approach is particularly useful when you need to query hierarchical data, compare rows within the same table, or find related records where the relationship is defined by columns within that very table. This article will guide you through the process, explaining the concepts and providing practical examples.
Understanding Self-Joins and LEFT OUTER JOIN
A self-join is a join operation where a table is joined with itself. To achieve this, you must use table aliases to distinguish between the two (or more) instances of the same table in your query. The LEFT OUTER JOIN
(or simply LEFT JOIN
) returns all rows from the 'left' table (the first table in the FROM
clause) and the matching rows from the 'right' table. If there is no match, it still returns the rows from the left table but with NULL
values for the columns of the right table. When self-joining, both 'left' and 'right' tables are actually the same underlying table, just referenced with different aliases.
flowchart TD A[Original Table] --> B{Alias 1 (Left Table)} A --> C{Alias 2 (Right Table)} B -- LEFT JOIN ON --> C C -- No Match --> D[NULLs for Right Table Columns] C -- Match --> E[Matching Right Table Columns] D --> F[Result Set] E --> F
Conceptual flow of a LEFT OUTER Self-Join
Practical Example: Employees and Managers
Consider a common scenario: an employees
table where each employee has a manager_id
that refers to another employee's employee_id
within the same table. We want to list all employees and, if they have a manager, display their manager's name. If an employee does not have a manager (e.g., the CEO), we still want to list them.
CREATE TABLE employees (
employee_id SERIAL PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
manager_id INT REFERENCES employees(employee_id)
);
INSERT INTO employees (first_name, last_name, manager_id) VALUES
('John', 'Doe', NULL), -- CEO
('Jane', 'Smith', 1),
('Peter', 'Jones', 1),
('Alice', 'Brown', 2),
('Bob', 'White', 2),
('Charlie', 'Green', 3);
SQL schema and sample data for the employees table
Performing the LEFT OUTER Self-Join
To retrieve all employees and their managers, we will join the employees
table with itself. One instance of the table will represent the 'employee' (e
), and the other will represent the 'manager' (m
). The LEFT JOIN
ensures that even employees without a manager are included in the result.
SELECT
e.first_name AS employee_first_name,
e.last_name AS employee_last_name,
m.first_name AS manager_first_name,
m.last_name AS manager_last_name
FROM
employees AS e
LEFT JOIN
employees AS m ON e.manager_id = m.employee_id;
SQL query performing a LEFT OUTER self-join to find employees and their managers
In this query:
employees AS e
is our 'left' table, representing the employees.employees AS m
is our 'right' table, representing the managers.ON e.manager_id = m.employee_id
is the join condition, linking an employee'smanager_id
to a manager'semployee_id
.- The
LEFT JOIN
ensures that all employees (e
) are returned. If an employee'smanager_id
does not match anyemployee_id
in them
alias (i.e.,manager_id
isNULL
), the manager's name fields (m.first_name
,m.last_name
) will beNULL
.
Extending with Multiple Self-Joins (Grand-Managers)
You can extend this concept to multiple levels. For instance, what if you want to find not only an employee's manager but also their manager's manager (grand-manager)? You can achieve this by adding another LEFT JOIN
to the same table.
SELECT
e.first_name AS employee_first_name,
e.last_name AS employee_last_name,
m.first_name AS manager_first_name,
m.last_name AS manager_last_name,
gm.first_name AS grand_manager_first_name,
gm.last_name AS grand_manager_last_name
FROM
employees AS e
LEFT JOIN
employees AS m ON e.manager_id = m.employee_id
LEFT JOIN
employees AS gm ON m.manager_id = gm.employee_id;
SQL query demonstrating multiple LEFT OUTER self-joins for employees, managers, and grand-managers
In this extended query:
employees AS e
is the employee.employees AS m
is the employee's direct manager.employees AS gm
is the manager's manager (grand-manager).- The second
LEFT JOIN
linksm.manager_id
togm.employee_id
. This meansgm
will beNULL
ifm
(the direct manager) does not have a manager, or ifm
itself isNULL
(i.e., the employeee
has no direct manager).
WITH RECURSIVE
for better readability and efficiency.