Find Managers Who Earn More Than All Their Direct Reports
Return the managers whose salary is higher than that of every employee reporting to them.
The challenge runs on the SQLabHub practice database (SQLite) and uses the employees table. You can solve it in the browser, with nothing to install.
The task
Find managers whose salary is greater than all their subordinates.
A correct answer returns 1 row with one column: id.
Tables used in this challenge
employees 120 rows
id INTEGER (PK) · first_name TEXT · last_name TEXT · email TEXT · department TEXT · department_id INTEGER · title TEXT · salary REAL · hire_date TEXT · manager_id INTEGER · city TEXT · status TEXT
| id | first_name | last_name | department | department_id | title | salary | hire_date | manager_id | city | status | |
|---|---|---|---|---|---|---|---|---|---|---|---|
The first rows of each table are shown. See how all the tables relate on the database schema page.
Expected output
| id |
|---|
The complete result: 1 row. This is the output of the model solution on the practice database.
What you practise
- Summarising many rows into one value with COUNT, SUM, AVG, MIN or MAX
- Grouping rows with GROUP BY to get one result row per group
- Filtering groups after aggregation with HAVING
- Combining rows from two tables on a matching key with an inner join
- Joining a table to itself under two aliases
Hint and approach
Try the challenge first. Open these only when you need them.
Show the hint
Self join + GROUP BY
Show the step-by-step approach
How the model solution is built, in the order the database evaluates it:
- Read from the
employeestable, under the aliasm. - Join
employeesagain, under the aliase, one.manager_id=m.id. - Group the rows by
m.id, so the result has one row for each value. - For each group, compute
MIN(m.salary > e.salary). - Filter the groups in
HAVING: keep those whereMIN(m.salary > e.salary)is true.
Model solution
Checking your session…
What to watch for
In SQLite a comparison evaluates to 1 or 0, so MIN(m.salary > e.salary) is 1 only when it is true for every report. That is a universal check written as an aggregate. The portable form is HAVING m.salary > MAX(e.salary).
- Self join. Without a condition such as a.id < b.id, a self join pairs every row with itself and lists each pair twice.
- INNER JOIN. An inner join drops rows that have no partner on the other side, and it repeats a row once for every match, which inflates SUM and COUNT.
- HAVING. Conditions on single rows belong in WHERE and conditions on aggregates in HAVING. Putting a row filter in HAVING works, but it groups rows that are about to be thrown away.
Related SQL challenges
- Compare Each Employee's Salary with Their Manager'sSimilar levelHard
- Find Orders with More Than One Payment RecordSimilar levelHard
- Find Pairs of Employees in the Same DepartmentEasierMedium
- Find Customers with More Than 3 Orders Using HAVINGEasierMedium
- Find Orders with More Than 3 Items Using HAVING SUMEasierMedium
Keep learning
- Lesson: SELF JOIN
- Lesson: INNER JOIN
- Lesson: HAVING Clause
- Lesson: GROUP BY
- All SQL practice challenges, by difficulty and topic
- SQL interview questions with answers
- SQL Playground: run any query on the same database