Join the employees table to itself. One copy plays the employee, the other plays their manager, matched by manager_id = id. Then keep rows where the employee's salary is higher.
Query
SELECT e.name AS employee, e.salary, m.name AS manager, m.salary AS manager_salary FROM employees e JOIN employees m ON e.manager_id = m.id WHERE e.salary > m.salary;
Four-row example
id name salary manager_id 1 Asha 150 NULL 2 Ben 160 1 3 Chen 120 1 4 Dia 100 3
Pairs after the join: Ben with Asha (160 vs 150), Chen with Asha (120 vs 150), Dia with Chen (100 vs 120). Asha has no manager, so no pair exists for her. Only Ben has a higher salary than his manager. Result: Ben.
Points worth saying
- An INNER JOIN is right here. Employees without a manager (the top of the tree) drop out, and that is what you want: you cannot earn more than a manager you do not have. If a question asks for "all employees and their manager, if any", use a LEFT JOIN.
- Use clear aliases.
eandmmake a self-join easy to read. Two copies of the same table with names likeaandbare easy to mix up. - The comparison is only with the direct manager. Comparing against any manager up the chain needs a recursive query.
Follow-ups
"Employees earning more than the average in their department" is a window or subquery question, not a self-join. "Managers with at least 3 reports" is a GROUP BY on manager_id with HAVING COUNT(*) >= 3, joined back for the name.