HackerRank SQL (Basic) certification
Merit Rewards
Merit Rewards is one of the five questions in the HackerRank SQL (Basic) certification test. It needs one join and two conditions, and both conditions have a small trap.
What the question asks
A company wants to reward strong performers in its HR division. Return the employee_ID and name of every employee who works in HR and earned a bonus of 5000 or more in the last quarter.
“5000 or more” includes 5000 itself.
Tables
Both tables use employee_ID as the primary key.
| Table | Column | What it holds |
|---|---|---|
employee_information |
employee_ID |
Employee id (primary key) |
employee_information |
name |
Employee’s name |
employee_information |
division |
Division the employee works in, such as HR |
last_quarter_bonus |
employee_ID |
Employee id (primary key) |
last_quarter_bonus |
bonus |
Bonus earned last quarter |
Solution
SELECT e.employee_ID, e.name
FROM employee_information e
JOIN last_quarter_bonus b ON b.employee_ID = e.employee_ID
WHERE e.division = 'HR'
AND b.bonus >= 5000;How it works
- The division is in
employee_informationand the bonus is inlast_quarter_bonus. Joining onemployee_IDputs them on one row. e.division = 'HR'keeps only HR staff.b.bonus >= 5000keeps bonuses of 5000 and above.- Both conditions are joined with
AND, because an employee needs to pass both.
My GitHub repo has WHERE ei.division LIKE 'HR'. Without a % or _, LIKE behaves the same as =, so it passes. But = says what you mean, so that’s what I use now.
Mistakes that fail the hidden tests
- Using
> 5000. An employee with a bonus of exactly 5000 must be in the list. In my test,>dropped Neha, who had exactly 5000. - Using
LIKE 'HR%'. This also matches divisions that start with HR, such as “HR Ops”. In my test it added Ravi from HR Ops. If you want an exact match, use=. - Forgetting the division filter. At least one public solution filters only on the bonus. That returns high earners from every division.
- Using a
LEFT JOINand keeping NULL bonuses. An HR employee with no bonus row did not earn 5000 or more. A plainJOINdrops them, which is what we want.
One small thing about case: MySQL compares text without caring about case by default, so division = 'hr' also matches “HR”. SQLite and PostgreSQL do care. Write 'HR' exactly and you’re safe everywhere.
Try it on sample data
These are my own rows. They include a bonus of exactly 5000, a bonus of 4999, an HR employee with no bonus row, a missing (NULL) bonus and a division called “HR Ops”.
employee_information
| employee_ID | name | division |
|---|---|---|
| 1 | Neha | HR |
| 2 | Vikram | HR |
| 3 | Pooja | HR |
| 4 | Arjun | Sales |
| 5 | Kavya | HR |
| 6 | Ravi | HR Ops |
| 7 | Simran | HR |
last_quarter_bonus
| employee_ID | bonus |
|---|---|
| 1 | 5000 |
| 2 | 4999 |
| 3 | 7200 |
| 4 | 9000 |
| 6 | 8000 |
| 7 | NULL |
Output
| employee_ID | name |
|---|---|
| 1 | Neha |
| 3 | Pooja |
Neha is in with exactly 5000. Vikram misses by 1. Arjun has a big bonus but works in Sales. Kavya has no bonus row. Ravi is in HR Ops, not HR. Simran’s bonus is NULL, and a NULL is never “5000 or more”. I ran this in MySQL and SQLite and got the same two rows.