Coding questions · Apple
Write queries to compute salary and budget stats
This set of tasks evaluates data manipulation and analytical competencies, specifically the ability to compute order-statistics on numeric columns, perform relational joins to enrich event records, and reason about constrained selection for maximizing hires using SQL and pandas.
You are given the following interview tasks. Write solutions in SQL and/or Python (pandas) as appropriate.
Task 1 — Second highest salary
You have a table:
employees
employee_idINT (PK)nameVARCHARsalaryINT
Return the second highest distinct salary.
- If there is no second distinct salary, return
NULL.
Required output
second_highest_salary(INT or NULL)
Task 2 — Merge two datasets
You are given two datasets that share a common key:
users
user_idINT (PK)countryVARCHARsignup_dateDATE
user_events
user_idINT (FK → users.user_id)event_timeTIMESTAMPevent_typeVARCHAR
Merge them so that each event row is enriched with user attributes.
- Keep only events that have a matching
user_idinusers(inner join).
Required output
user_id,country,signup_date,event_time,event_type
Task 3 — “Run out the budget” (maximize hires)
You have a list/table of employees with their salaries and a total hiring budget B.
- Each employee costs exactly their
salary. - You can hire at most once per employee.
- Goal: maximize the number of employees hired without exceeding the budget.
Input
employees(employee_id, salary)and an integerB
Required output
max_hires(INT)
Clarify any assumptions you need (e.g., what to do if B <= 0).
Merge two employee datasets (deduplicate by employee_id)
You are given two employee datasets from two different sources: employees_source_a and employees_source_b. Both tables have the same columns.
Create a merged result set that contains exactly one row per employee_id using these rules:
- If an employee_id exists in both tables, keep the row with the later updated_at date.
- If updated_at is the same in both tables (edge case), prefer the row from employees_source_b.
- If an employee_id exists in only one table, keep that row.
Return the merged employees with columns: employee_id, employee_name, dept_id, salary, updated_at, chosen_source. Sort by employee_id.
Table employees_source_a
| column | type | constraints |
|---|---|---|
| employee_id | INT | NOT NULL |
| employee_name | VARCHAR(50) | NOT NULL |
| dept_id | INT | NOT NULL |
| salary | DECIMAL(12,2) | NOT NULL |
| updated_at | DATE | NOT NULL |
Sample data:
| dept_id | employee_id | employee_name | salary | updated_at |
|---|---|---|---|---|
| 10 | 1 | Alice | 120000 | 2025-01-15 |
| 10 | 2 | Bob | 90000 | 2025-01-15 |
| 20 | 3 | Cara | 110000 | 2025-01-15 |
| 30 | 4 | Dan | 105000 | 2025-01-15 |
Table employees_source_b
| column | type | constraints |
|---|---|---|
| employee_id | INT | NOT NULL |
| employee_name | VARCHAR(50) | NOT NULL |
| dept_id | INT | NOT NULL |
| salary | DECIMAL(12,2) | NOT NULL |
| updated_at | DATE | NOT NULL |
Sample data:
| dept_id | employee_id | employee_name | salary | updated_at |
|---|---|---|---|---|
| 20 | 3 | Cara | 115000 | 2025-03-01 |
| 20 | 5 | Evan | 95000 | 2025-03-01 |
| 30 | 6 | Fiona | 105000 | 2025-03-01 |
| 40 | 7 | George | 130000 | 2025-03-01 |
Expected output
One row per employee_id after merging and deduplicating across both sources. Includes a chosen_source column indicating which source was kept.
| chosen_source | dept_id | employee_id | employee_name | salary | updated_at |
|---|---|---|---|---|---|
| A | 10 | 1 | Alice | 120000 | 2025-01-15 |
| A | 10 | 2 | Bob | 90000 | 2025-01-15 |
| B | 20 | 3 | Cara | 115000 | 2025-03-01 |
| A | 30 | 4 | Dan | 105000 | 2025-01-15 |
| B | 20 | 5 | Evan | 95000 | 2025-03-01 |
| B | 30 | 6 | Fiona | 105000 | 2025-03-01 |
| B | 40 | 7 | George | 130000 | 2025-03-01 |
Hints
- UNION ALL the two sources and rank rows per employee_id.
- Use ROW_NUMBER() with ORDER BY updated_at DESC, then a source priority tie-breaker.
Find the second highest distinct salary (after merging)
Using the same two source tables (employees_source_a and employees_source_b), first create the merged employee dataset using the same deduplication rules as in the previous task (latest updated_at wins; tie goes to source B).
From the merged dataset, return the employee(s) who have the second highest DISTINCT salary (i.e., if the highest salary is 130k, the second highest distinct might be 120k even if multiple people share 105k). Return: employee_id, employee_name, salary. Sort by employee_id.
Table employees_source_a
| column | type | constraints |
|---|---|---|
| employee_id | INT | NOT NULL |
| employee_name | VARCHAR(50) | NOT NULL |
| dept_id | INT | NOT NULL |
| salary | DECIMAL(12,2) | NOT NULL |
| updated_at | DATE | NOT NULL |
Sample data:
| dept_id | employee_id | employee_name | salary | updated_at |
|---|---|---|---|---|
| 10 | 1 | Alice | 120000 | 2025-01-15 |
| 10 | 2 | Bob | 90000 | 2025-01-15 |
| 20 | 3 | Cara | 110000 | 2025-01-15 |
| 30 | 4 | Dan | 105000 | 2025-01-15 |
Table employees_source_b
| column | type | constraints |
|---|---|---|
| employee_id | INT | NOT NULL |
| employee_name | VARCHAR(50) | NOT NULL |
| dept_id | INT | NOT NULL |
| salary | DECIMAL(12,2) | NOT NULL |
| updated_at | DATE | NOT NULL |
Sample data:
| dept_id | employee_id | employee_name | salary | updated_at |
|---|---|---|---|---|
| 20 | 3 | Cara | 115000 | 2025-03-01 |
| 20 | 5 | Evan | 95000 | 2025-03-01 |
| 30 | 6 | Fiona | 105000 | 2025-03-01 |
| 40 | 7 | George | 130000 | 2025-03-01 |
Expected output
Employee(s) whose salary is the second highest distinct salary in the merged dataset.
| employee_id | employee_name | salary |
|---|---|---|
| 1 | Alice | 120000 |
Hints
- Use a CTE to build the merged dataset first.
- Use DENSE_RANK() to handle distinct salary ranking and ties correctly.
Find departments that are over budget (salary expense)
Using the merged employee dataset created from employees_source_a and employees_source_b (same deduplication rules: latest updated_at wins; tie goes to source B), treat each employee's salary as an expense.
Given a department_budget table, compute total salary expense per department and find departments where salary_expense > annual_budget.
Return: dept_id, dept_name, annual_budget, salary_expense, over_budget_amount (salary_expense - annual_budget). Sort by over_budget_amount descending, then dept_id ascending.
Table employees_source_a
| column | type | constraints |
|---|---|---|
| employee_id | INT | NOT NULL |
| employee_name | VARCHAR(50) | NOT NULL |
| dept_id | INT | NOT NULL |
| salary | DECIMAL(12,2) | NOT NULL |
| updated_at | DATE | NOT NULL |
Sample data:
| dept_id | employee_id | employee_name | salary | updated_at |
|---|---|---|---|---|
| 10 | 1 | Alice | 120000 | 2025-01-15 |
| 10 | 2 | Bob | 90000 | 2025-01-15 |
| 20 | 3 | Cara | 110000 | 2025-01-15 |
| 30 | 4 | Dan | 105000 | 2025-01-15 |
Table employees_source_b
| column | type | constraints |
|---|---|---|
| employee_id | INT | NOT NULL |
| employee_name | VARCHAR(50) | NOT NULL |
| dept_id | INT | NOT NULL |
| salary | DECIMAL(12,2) | NOT NULL |
| updated_at | DATE | NOT NULL |
Sample data:
| dept_id | employee_id | employee_name | salary | updated_at |
|---|---|---|---|---|
| 20 | 3 | Cara | 115000 | 2025-03-01 |
| 20 | 5 | Evan | 95000 | 2025-03-01 |
| 30 | 6 | Fiona | 105000 | 2025-03-01 |
| 40 | 7 | George | 130000 | 2025-03-01 |
Table departments
| column | type | constraints |
|---|---|---|
| dept_id | INT | PRIMARY KEY, NOT NULL |
| dept_name | VARCHAR(50) | NOT NULL |
Sample data:
| dept_id | dept_name |
|---|---|
| 10 | Ads Ops |
| 20 | Measurement |
| 30 | Creative |
| 40 | Sales |
Table department_budget
| column | type | constraints |
|---|---|---|
| dept_id | INT | PRIMARY KEY, NOT NULL |
| annual_budget | DECIMAL(12,2) | NOT NULL |
Sample data:
| annual_budget | dept_id |
|---|---|
| 200000 | 10 |
| 300000 | 20 |
| 205000 | 30 |
| 120000 | 40 |
Expected output
Departments where total merged salary expense exceeds the annual budget, including the computed over_budget_amount.
| annual_budget | dept_id | dept_name | over_budget_amount | salary_expense |
|---|---|---|---|---|
| 200000 | 10 | Ads Ops | 10000 | 210000 |
| 120000 | 40 | Sales | 10000 | 130000 |
| 205000 | 30 | Creative | 5000 | 210000 |
Hints
- Build the merged employee dataset first, then aggregate salaries by dept_id.
- Compare the aggregate expense to department_budget and filter where expense is greater.