Lesson 51 of 60 – Self Join
85%

SQL Self Join

A SELF JOIN is a join where a table is joined with itself. It is useful when records in the same table are related to each other. For example, an employee table may contain both employees and their managers.

Note: SQL does not have a separate SELF JOIN keyword. A self join is created by using a normal JOIN and giving the same table two different aliases.

1. What is a Self Join?

A Self Join joins a table with itself. The table is treated as two separate tables using different aliases.

SELECT
    e.employee_name,
    m.employee_name AS manager_name
FROM employees AS e
JOIN employees AS m
ON e.manager_id = m.employee_id;

Here, the employees table is used twice: once for employees and once for managers.

2. Why Use a Self Join?

A Self Join is useful when records in the same table have relationships with other records in that table.

  • Employees and managers
  • Students and mentors
  • Categories and parent categories
  • Employees and supervisors
  • Products and related products

3. Basic Self Join Syntax

The basic syntax is:

SELECT columns
FROM table AS a
JOIN table AS b
ON a.column = b.column;

The same table is given two different aliases so SQL can distinguish between the two references.

4. Self Join with Employees and Managers

Suppose an employees table contains manager_id.

SELECT
    e.employee_name,
    m.employee_name AS manager_name
FROM employees AS e
JOIN employees AS m
ON e.manager_id = m.employee_id;

The first alias represents the employee and the second alias represents the manager.

5. Understanding Table Aliases

Aliases are essential in a Self Join because the same table appears twice.

FROM employees AS e
JOIN employees AS m

Here:

  • e = employee
  • m = manager

6. The ON Condition

The ON condition defines how records within the same table are related.

ON e.manager_id = m.employee_id

This means the manager ID stored for an employee must match another employee's employee ID.

7. Self Join with LEFT JOIN

A LEFT JOIN can be used when you want to display every employee, including employees who do not have a manager.

SELECT
    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;

Employees without a manager will have a NULL manager name.

8. Self Join with INNER JOIN

An INNER JOIN returns only employees who have a matching manager.

SELECT
    e.employee_name,
    m.employee_name AS manager_name
FROM employees AS e
INNER JOIN employees AS m
ON e.manager_id = m.employee_id;

9. Self Join with Specific Columns

You can select additional columns from both references of the same table.

SELECT
    e.employee_id,
    e.employee_name,
    m.employee_id AS manager_id,
    m.employee_name AS manager_name
FROM employees AS e
LEFT JOIN employees AS m
ON e.manager_id = m.employee_id;

10. Self Join with WHERE

A WHERE condition can filter records from a Self Join.

SELECT
    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
WHERE e.department = 'IT';

This displays employees from the IT department and their managers.

11. Self Join with ORDER BY

The result can be sorted using columns from the employee reference.

SELECT
    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_name;

12. Finding Employees Without Managers

A LEFT JOIN can find employees who do not have a manager.

SELECT
    e.employee_name
FROM employees AS e
LEFT JOIN employees AS m
ON e.manager_id = m.employee_id
WHERE e.manager_id IS NULL;

This can identify top-level employees or employees whose manager has not been assigned.

13. Finding Employees with Managers

You can find employees who have a manager using a condition on manager_id.

SELECT
    e.employee_name,
    m.employee_name AS manager_name
FROM employees AS e
INNER JOIN employees AS m
ON e.manager_id = m.employee_id
WHERE e.manager_id IS NOT NULL;

14. Self Join for Employee Hierarchy

A Self Join can display a simple organizational hierarchy.

SELECT
    e.employee_name AS employee,
    m.employee_name AS manager
FROM employees AS e
LEFT JOIN employees AS m
ON e.manager_id = m.employee_id;

The result shows each employee and the manager assigned to that employee.

15. Self Join with Salary Comparison

A Self Join can compare the salary of an employee with the salary of another employee.

SELECT
    e.employee_name,
    e.salary,
    m.employee_name AS manager_name,
    m.salary AS manager_salary
FROM employees AS e
INNER JOIN employees AS m
ON e.manager_id = m.employee_id;

16. Finding Employees Earning More Than Their Managers

A Self Join can compare two rows from the same table.

SELECT
    e.employee_name,
    e.salary,
    m.employee_name AS manager_name,
    m.salary AS manager_salary
FROM employees AS e
INNER JOIN employees AS m
ON e.manager_id = m.employee_id
WHERE e.salary > m.salary;

This returns employees whose salary is greater than their manager's salary.

17. Finding Employees Earning Less Than Managers

The same technique can find employees whose salary is lower than their manager's salary.

SELECT
    e.employee_name,
    e.salary,
    m.employee_name AS manager_name,
    m.salary AS manager_salary
FROM employees AS e
INNER JOIN employees AS m
ON e.manager_id = m.employee_id
WHERE e.salary < m.salary;

18. Self Join for Same Department

A Self Join can find employees working in the same department.

SELECT
    e1.employee_name AS employee1,
    e2.employee_name AS employee2,
    e1.department
FROM employees AS e1
INNER JOIN employees AS e2
ON e1.department = e2.department
AND e1.employee_id < e2.employee_id;

The ID condition helps avoid returning the same employee pair in reverse order.

19. Comparing Two Rows from the Same Table

Self Join allows us to compare values from two different rows of the same table.

SELECT
    a.employee_name AS employee_a,
    b.employee_name AS employee_b,
    a.salary AS salary_a,
    b.salary AS salary_b
FROM employees AS a
INNER JOIN employees AS b
ON a.department = b.department
AND a.employee_id < b.employee_id;

20. Self Join with CASE

CASE can be combined with Self Join to classify relationships.

SELECT
    e.employee_name,
    m.employee_name AS manager_name,
    CASE
        WHEN e.salary > m.salary THEN 'Higher Salary'
        WHEN e.salary < m.salary THEN 'Lower Salary'
        ELSE 'Same Salary'
    END AS salary_status
FROM employees AS e
INNER JOIN employees AS m
ON e.manager_id = m.employee_id;

21. Self Join with Aggregate Functions

Self Join can be combined with aggregate functions to count related records.

SELECT
    m.employee_name AS manager,
    COUNT(e.employee_id) AS team_size
FROM employees AS m
LEFT JOIN employees AS e
ON e.manager_id = m.employee_id
GROUP BY m.employee_id, m.employee_name;

This counts the number of employees reporting to each manager.

22. Self Join with GROUP BY

GROUP BY can be used to create manager-wise reports.

SELECT
    m.employee_name AS manager,
    COUNT(e.employee_id) AS total_employees
FROM employees AS m
LEFT JOIN employees AS e
ON e.manager_id = m.employee_id
GROUP BY m.employee_name;

23. Self Join with HAVING

HAVING can filter managers based on the number of employees reporting to them.

SELECT
    m.employee_name AS manager,
    COUNT(e.employee_id) AS team_size
FROM employees AS m
LEFT JOIN employees AS e
ON e.manager_id = m.employee_id
GROUP BY m.employee_name
HAVING team_size > 5;

This returns managers with more than five employees in their team.

24. Self Join for Parent-Child Data

Self Join is not limited to employees. It is also useful for parent-child relationships.

SELECT
    child.category_name AS category,
    parent.category_name AS parent_category
FROM categories AS child
LEFT JOIN categories AS parent
ON child.parent_id = parent.category_id;

Here, the same categories table stores both categories and parent categories.

25. Self Join for Related Products

A Self Join can be used when products are related to other products in the same table.

SELECT
    p.product_name,
    r.product_name AS related_product
FROM products AS p
LEFT JOIN products AS r
ON p.related_product_id = r.product_id;

26. Avoiding Duplicate Pairs

When comparing records within the same table, the same pair can appear twice. A condition such as a.id < b.id can prevent duplicate pairs.

SELECT
    a.employee_name AS employee1,
    b.employee_name AS employee2
FROM employees AS a
INNER JOIN employees AS b
ON a.department = b.department
AND a.employee_id < b.employee_id;

27. Common Self Join Mistake

A common mistake is using the same alias for both references to the table.

-- Incorrect
FROM employees AS e
JOIN employees AS e

Each reference must have a different alias.

-- Correct
FROM employees AS e
JOIN employees AS m

28. Self Join vs Normal Join

Normal JOIN: Usually joins different tables.

Self Join: Joins a table with itself using different aliases.

-- Normal JOIN
FROM students s
JOIN courses c
ON s.course_id = c.id;

-- Self JOIN
FROM employees e
JOIN employees m
ON e.manager_id = m.employee_id;

29. Practical Employee-Manager Report

A practical employee-manager report can be created using a Self Join.

SELECT
    e.employee_id,
    e.employee_name AS employee,
    e.department,
    e.salary,
    m.employee_name AS manager,
    m.salary AS manager_salary
FROM employees AS e
LEFT JOIN employees AS m
ON e.manager_id = m.employee_id
ORDER BY e.employee_name;

This report displays each employee and the manager assigned to them.

30. Complete Self Join Example

The following example combines a Self Join with CASE and calculations.

SELECT
    e.employee_id,
    e.employee_name AS employee,
    e.department,
    e.salary AS employee_salary,
    m.employee_name AS manager,
    m.salary AS manager_salary,
    CASE
        WHEN e.manager_id IS NULL THEN 'Top Level'
        WHEN e.salary > m.salary THEN 'Higher Than Manager'
        WHEN e.salary < m.salary THEN 'Lower Than Manager'
        ELSE 'Same As Manager'
    END AS employee_status
FROM employees AS e
LEFT JOIN employees AS m
ON e.manager_id = m.employee_id
ORDER BY e.employee_name;

This query displays the employee, manager, salaries, and a calculated relationship status.

📌 Key Points

  • A Self Join joins a table with itself.
  • SQL does not have a separate SELF JOIN keyword.
  • Different table aliases are required to distinguish the two references.
  • Self Join is useful for employee-manager relationships.
  • Self Join is useful for parent-child category relationships.
  • Self Join can compare values between two rows of the same table.
  • LEFT JOIN can be used to include records without a related record.
  • INNER JOIN can be used when only matching records are required.
  • Self Join can be combined with WHERE, ORDER BY, GROUP BY, and HAVING.
  • Aggregate functions can be used to count related records.
  • Self Join can be used to compare salaries or other values.
  • Conditions such as a.id < b.id can prevent duplicate pairs.
  • Different aliases must be used for each reference to the same table.
  • Self Join is useful for hierarchical and relational data stored in one table.

🧠 Quick Quiz

Question: What is a SQL Self Join used for?