MySQL SELF JOIN: Syntax and Examples
Learn how MySQL SELF JOIN uses table aliases to compare rows in one table, with an employee-manager hierarchy and pair-matching example.
A self join uses a table twice in the same query to compare or relate rows in that table. MySQL does not have a separate SELF JOIN keyword; write a regular JOIN and give each table reference its own alias. For the general join forms, see MySQL JOIN.
MySQL SELF JOIN syntax
SELECT left_alias.column_name, right_alias.column_name
FROM table_name AS left_alias
JOIN table_name AS right_alias
ON left_alias.key_column = right_alias.key_column;
The aliases distinguish the two roles played by the same table. Always qualify column names with the correct alias when both references contain columns with the same names.
Match employees with their managers
An employee table can store each manager as another employee’s ID. Create and populate a small example table:
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
employee_name VARCHAR(80) NOT NULL,
manager_id INT NULL
);
INSERT INTO employees (employee_id, employee_name, manager_id) VALUES
(1, 'Ava Chen', NULL),
(2, 'Leo Kim', 1),
(3, 'Mia Park', 1),
(4, 'Noah Liu', 2),
(5, 'Ivy Wu', 2);
Use employees once as the employee (e) and again as the manager (m):
SELECT
e.employee_id,
e.employee_name,
m.employee_name AS manager_name
FROM employees AS e
LEFT JOIN employees AS m
ON e.manager_id = m.employee_id
ORDER BY e.employee_id;
The query returns:
+-------------+---------------+--------------+
| employee_id | employee_name | manager_name |
+-------------+---------------+--------------+
| 1 | Ava Chen | NULL |
| 2 | Leo Kim | Ava Chen |
| 3 | Mia Park | Ava Chen |
| 4 | Noah Liu | Leo Kim |
| 5 | Ivy Wu | Leo Kim |
+-------------+---------------+--------------+The LEFT JOIN keeps Ava’s row even though she has no manager. Replacing it with INNER JOIN returns only employees that have a matching manager row.
Find pairs of rows in the same table
A self join can also find pairs of products that share a category. The condition p1.product_id < p2.product_id prevents a product from matching itself and returns each pair only once:
SELECT
p1.product_id AS product_a,
p2.product_id AS product_b,
p1.category_id
FROM products AS p1
JOIN products AS p2
ON p1.category_id = p2.category_id
AND p1.product_id < p2.product_id;
This query assumes product_id uniquely identifies each product. Without the < condition, the result could include each product paired with itself and both orders of the same pair.
Common SELF JOIN mistakes
- Reusing the table name without aliases: Give every reference to the table a distinct alias, such as
eandm. - Leaving columns unqualified: Use
e.employee_idorm.employee_idso MySQL knows which reference you mean. - Choosing the wrong join type: Use
LEFT JOINwhen rows without a match must remain; useINNER JOINwhen only matched pairs are needed. - Joining on an incomplete condition: Include the key comparison in
ON; an omitted join condition can create many unintended row combinations.
A self join connects rows using one relationship at a time. To walk a hierarchy with an unknown number of levels, use a recursive CTE.
For the table-alias and join syntax, see the MySQL 8.4 Reference Manual: JOIN Clause and Using More Than One Table.