LeetCode SQL Interview Questions Solved in MySQL
2025-08-12
SQL on LeetCode is very pattern driven. If you learn a handful of templates for joins, window functions, filtering, and aggregation, you can solve most questions quickly. Below are clean MySQL solutions to common interview tasks with short notes you can repeat out loud.
I use sample schemas similar to LeetCode. You can paste each snippet into a MySQL client and adapt names if your table differs.
1) Second Highest Salary
Goal: return the second distinct highest salary or NULL
if it does not exist.
SELECT
(
SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
LIMIT 1 OFFSET 1
) AS SecondHighestSalary;
Why this works: LIMIT 1 OFFSET 1
skips the top distinct salary. If the table has fewer than two distinct values, the subquery returns NULL
.
Window alternative:
SELECT MAX(salary) AS SecondHighestSalary
FROM (
SELECT salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM Employee
) t
WHERE rnk = 2;
2) Nth Highest Salary (parameterized)
-- set @N := 3; -- example
SET @N := 3;
SELECT (
SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
LIMIT 1 OFFSET @N - 1
) AS NthHighestSalary;
If your interviewer allows window functions:
SET @N := 3;
WITH ranked AS (
SELECT salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM Employee
)
SELECT salary AS NthHighestSalary
FROM ranked
WHERE rnk = @N;
3) Department Highest Salary
Goal: for each department, return the employee with the top salary. If ties exist, return all.
SELECT d.name AS Department, e.name AS Employee, e.salary
FROM Employee e
JOIN Department d ON e.departmentId = d.id
JOIN (
SELECT departmentId, MAX(salary) AS max_sal
FROM Employee
GROUP BY departmentId
) m ON m.departmentId = e.departmentId AND m.max_sal = e.salary
ORDER BY d.name, e.name;
Why: precompute each department max, then join back to select matching rows.
4) Customers Who Never Order
SELECT c.name AS Customers
FROM Customers c
LEFT JOIN Orders o ON o.customerId = c.id
WHERE o.id IS NULL
ORDER BY c.name;
Pattern: left join then filter NULL
on the right table to find non matches.
5) Duplicate Emails
SELECT email
FROM Person
GROUP BY email
HAVING COUNT(*) > 1;
Tip: use HAVING
on aggregates. Do not try WHERE COUNT(*) > 1
.
6) Rising Temperature
Goal: find days where temperature is higher than the previous day.
SELECT w1.id
FROM Weather w1
JOIN Weather w0
ON DATE_SUB(w1.recordDate, INTERVAL 1 DAY) = w0.recordDate
WHERE w1.temperature > w0.temperature
ORDER BY w1.id;
Window alternative:
SELECT id
FROM (
SELECT id,
temperature,
LAG(temperature) OVER (ORDER BY recordDate) AS prev_temp
FROM Weather
) t
WHERE temperature > prev_temp;
7) Activity Rank per User
Goal: for each user, order activities by event time and keep only the first row.
SELECT user_id, activity, event_time
FROM (
SELECT user_id, activity, event_time,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_time) AS rn
FROM Activity
) t
WHERE rn = 1;
Speaking point: partition by user, order by time, pick rank 1.
8) Employees Earning More Than Their Manager
SELECT e.name AS Employee
FROM Employee e
JOIN Employee m ON m.id = e.managerId
WHERE e.salary > m.salary
ORDER BY e.name;
Pattern: self join table to itself.
9) Friend Requests I: Overall Acceptance Rate
Tables: FriendRequest(sender_id, send_to_id, request_date)
and RequestAccepted(sender_id, receive_id, accept_date)
.
SELECT
ROUND(
IFNULL(
(SELECT COUNT(*) FROM RequestAccepted) /
NULLIF((SELECT COUNT(*) FROM FriendRequest), 0),
0
),
2
) AS accept_rate;
Notes: NULLIF
avoids division by zero. IFNULL
handles no data case. Round to two decimals if asked.
10) Top 3 Salaries per Department
SELECT d.name AS Department, e.name AS Employee, e.salary
FROM (
SELECT *,
DENSE_RANK() OVER (PARTITION BY departmentId ORDER BY salary DESC) AS rnk
FROM Employee
) e
JOIN Department d ON d.id = e.departmentId
WHERE e.rnk <= 3
ORDER BY d.name, e.salary DESC, e.name;
Pattern: window rank inside a subquery, then filter by rank.
11) Consecutive Numbers
Goal: find numbers that appear at least three times in a row.
SELECT DISTINCT l1.num AS ConsecutiveNums
FROM Logs l1
JOIN Logs l2 ON l2.id = l1.id + 1 AND l2.num = l1.num
JOIN Logs l3 ON l3.id = l1.id + 2 AND l3.num = l1.num;
Why: align rows by offset using self joins.
12) Trips and Users: Cancellation Rate
Tables: Trips(id, client_id, driver_id, status, request_at)
and Users(users_id, banned, role)
.
SELECT
t.request_at AS Day,
ROUND(
AVG(CASE WHEN t.status IN ('cancelled_by_client', 'cancelled_by_driver') THEN 1 ELSE 0 END),
2
) AS CancellationRate
FROM Trips t
JOIN Users c ON c.users_id = t.client_id AND c.banned = 'No'
JOIN Users d ON d.users_id = t.driver_id AND d.banned = 'No'
GROUP BY t.request_at
ORDER BY t.request_at;
Trick: average of a 0 or 1 expression yields the rate.
13) Ranking Scores
Goal: dense ranks for scores.
SELECT score,
DENSE_RANK() OVER (ORDER BY score DESC) AS `rank`
FROM Scores
ORDER BY score DESC;
14) Sales Person Without Orders for Company X
SELECT s.name
FROM SalesPerson s
WHERE NOT EXISTS (
SELECT 1
FROM Orders o
JOIN Company c ON c.com_id = o.com_id
WHERE o.sales_id = s.sales_id
AND c.name = 'RED'
);
Pattern: NOT EXISTS
for anti join logic.
15) Employees Project Allocation: Longest Streak
Goal: for each employee, find the longest run of consecutive days worked.
WITH t AS (
SELECT employee_id,
work_date,
DATE_SUB(work_date, INTERVAL ROW_NUMBER() OVER (
PARTITION BY employee_id ORDER BY work_date
) DAY) AS grp
FROM Attendance
)
SELECT employee_id,
MAX(COUNT(*)) OVER (PARTITION BY employee_id) AS longest_streak
FROM t
GROUP BY employee_id, grp;
Idea: subtract the row number from the date to create equal keys for consecutive runs.
16) Average Time between Visits
Goal: compute average seconds between consecutive events per user.
SELECT user_id,
ROUND(AVG(TIMESTAMPDIFF(SECOND, prev_time, event_time)), 2) AS avg_secs_between
FROM (
SELECT user_id,
event_time,
LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_time
FROM Events
) x
WHERE prev_time IS NOT NULL
GROUP BY user_id;
17) Rolling 7 Day Active Users
SELECT d.dt,
COUNT(DISTINCT a.user_id) AS dau_7d
FROM Dates d
LEFT JOIN Activity a
ON a.activity_date BETWEEN DATE_SUB(d.dt, INTERVAL 6 DAY) AND d.dt
GROUP BY d.dt
ORDER BY d.dt;
Interview note: if Dates table is not present, generate dates on the fly or constrain to dates present in Activity.
18) Percentile by Category
Goal: for each category, tag values at or above the 90th percentile.
WITH ranked AS (
SELECT category, value,
PERCENT_RANK() OVER (PARTITION BY category ORDER BY value) AS pr
FROM Metrics
)
SELECT category, value,
CASE WHEN pr >= 0.9 THEN 'top_decile' ELSE 'other' END AS bucket
FROM ranked;
MySQL supports PERCENT_RANK
from 8.0 onward.
19) Running Total per User
SELECT user_id,
event_time,
amount,
SUM(amount) OVER (PARTITION BY user_id ORDER BY event_time
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM Payments
ORDER BY user_id, event_time;
20) Windowed Top N with Ties
Goal: top 2 orders per customer by amount with ties included.
SELECT *
FROM (
SELECT customer_id, order_id, amount,
DENSE_RANK() OVER (PARTITION BY customer_id ORDER BY amount DESC) AS rnk
FROM Orders
) t
WHERE rnk <= 2
ORDER BY customer_id, amount DESC, order_id;
Common MySQL pitfalls in interviews
- Using
WHERE
to filter aggregates. UseHAVING
. - Forgetting
DISTINCT
when a question demands unique values. - Joining without a key and creating duplicates that inflate counts.
- Using
RANK
when you wantedDENSE_RANK
. Know the difference. - Division by zero in rates. Protect with
NULLIF
and wrap withIFNULL
. - Relying on implicit grouping behavior. Always list all non aggregated columns in
GROUP BY
for clarity. - Sorting after
LIMIT
with noORDER BY
. MySQL will not guarantee order unless you specify it.
Quick study checklist
- Left join anti patterns for “never did X”
- Window functions for rank, lag, lead, cumulative sum
- Self joins for previous day or consecutive rows
- Subqueries with
IN
,EXISTS
,NOT EXISTS
- Aggregation with
GROUP BY
andHAVING
- Date arithmetic with
DATE_SUB
,TIMESTAMPDIFF
Work through these patterns and most SQL interview problems will feel familiar.
If you want a helper while practicing that can overlay a clean solution and short explanation when you are stuck, you can use a lightweight tool that captures the prompt and shows an outline you can study and explain back. It keeps you focused on patterns instead of spinning your wheels.
Try StealthCoder when you want a quick solution outline for SQL prompts: https://stealthcoder.app