🎯 LeetCode Top SQL 50 – Complete Solutions

Detailed view of colorful programming code on a computer screen.

🎯 LeetCode Top SQL 50

Complete Solutions Guide with Explanations

SELECT Problems

1. Recyclable and Low Fat Products

#1757

Find products that are both low fat and recyclable.

SELECT product_id
FROM Products
WHERE low_fats = 'Y'
  AND recyclable = 'Y';

2. Find Customer Referee

#584

Find names of customers not referred by customer with id = 2.

SELECT name
FROM Customer
WHERE referee_id != 2 
   OR referee_id IS NULL;

3. Big Countries

#595

Find name, population, and area of big countries (area >= 3M or population >= 25M).

SELECT name, population, area
FROM World
WHERE area >= 3000000
   OR population >= 25000000;

4. Article Views I

#1148

Find authors who viewed their own articles.

SELECT DISTINCT author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY author_id;

5. Invalid Tweets

#1683

Find tweet IDs with content longer than 15 characters.

SELECT tweet_id
FROM Tweets
WHERE LENGTH(content) > 15;

JOINS

6. Replace Employee ID With The Unique Identifier

#1378

Show unique_id and name for all employees.

SELECT eu.unique_id, e.name
FROM Employees e
LEFT JOIN EmployeeUNI eu ON e.id = eu.id;

7. Product Sales Analysis I

#1068

Report product_name, year, and price for each sale.

SELECT p.product_name, s.year, s.price
FROM Sales s
LEFT JOIN Product p ON s.product_id = p.product_id;

8. Customer Who Visited but Did Not Make Any Transactions

#1581

Find customer_id and count of visits without transactions.

SELECT customer_id, COUNT(*) AS count_no_trans
FROM Visits
WHERE visit_id NOT IN (
    SELECT DISTINCT visit_id FROM Transactions
)
GROUP BY customer_id;

9. Rising Temperature

#197

Find IDs with higher temperature than previous day.

SELECT w1.id
FROM Weather w1
JOIN Weather w2 
  ON DATEDIFF(w1.recordDate, w2.recordDate) = 1
WHERE w1.temperature > w2.temperature;

10. Average Time of Process per Machine

#1661

Calculate average processing time per machine.

SELECT machine_id, 
       ROUND(AVG(end_time - start_time), 3) AS processing_time
FROM (
    SELECT machine_id, process_id,
           MAX(CASE WHEN activity_type = 'start' 
               THEN timestamp END) AS start_time,
           MAX(CASE WHEN activity_type = 'end' 
               THEN timestamp END) AS end_time
    FROM Activity
    GROUP BY machine_id, process_id
) AS subq
GROUP BY machine_id;

11. Employee Bonus

#577

Report name and bonus of employees with bonus < 1000.

SELECT e.name, b.bonus
FROM Employee e
LEFT JOIN Bonus b ON e.empId = b.empId
WHERE b.bonus < 1000 OR b.bonus IS NULL;

12. Students and Examinations

#1280

Find number of exams each student attended for each subject.

SELECT s.student_id, s.student_name, 
       sub.subject_name, 
       COUNT(e.subject_name) AS attended_exams
FROM Students s
CROSS JOIN Subjects sub
LEFT JOIN Examinations e 
  ON s.student_id = e.student_id 
  AND sub.subject_name = e.subject_name
GROUP BY s.student_id, s.student_name, sub.subject_name
ORDER BY s.student_id, sub.subject_name;

13. Managers with at Least 5 Direct Reports

#570

Find managers with at least 5 direct reports.

SELECT name
FROM Employee
WHERE id IN (
    SELECT managerId
    FROM Employee
    GROUP BY managerId
    HAVING COUNT(*) >= 5
);

14. Confirmation Rate

#1934

Calculate confirmation rate for each user.

SELECT s.user_id,
       ROUND(COALESCE(
           SUM(CASE WHEN c.action = 'confirmed' THEN 1 END) 
           / COUNT(c.action), 0), 2) AS confirmation_rate
FROM Signups s
LEFT JOIN Confirmations c ON s.user_id = c.user_id
GROUP BY s.user_id;

Aggregate Functions

15. Not Boring Movies

#620

Report movies with odd ID, not boring description, ordered by rating.

SELECT *
FROM Cinema
WHERE id % 2 = 1 
  AND description != 'boring'
ORDER BY rating DESC;

16. Average Selling Price

#1251

Find average selling price for each product.

SELECT p.product_id,
       ROUND(SUM(p.price * u.units) / SUM(u.units), 2) 
       AS average_price
FROM Prices p
LEFT JOIN UnitsSold u 
  ON p.product_id = u.product_id
  AND u.purchase_date BETWEEN p.start_date AND p.end_date
GROUP BY p.product_id;

17. Project Employees I

#1075

Report average experience years for each project.

SELECT p.project_id, 
       ROUND(AVG(e.experience_years), 2) AS average_years
FROM Project p
LEFT JOIN Employee e ON p.employee_id = e.employee_id
GROUP BY p.project_id;

18. Percentage of Users Attended a Contest

#1633

Find percentage of users registered for each contest.

SELECT contest_id,
       ROUND(COUNT(DISTINCT user_id) * 100.0 
           / (SELECT COUNT(*) FROM Users), 2) AS percentage
FROM Register
GROUP BY contest_id
ORDER BY percentage DESC, contest_id ASC;

19. Queries Quality and Percentage

#1211

Calculate quality and poor_query_percentage for each query.

SELECT query_name,
       ROUND(AVG(rating / position), 2) AS quality,
       ROUND(SUM(CASE WHEN rating < 3 THEN 1 ELSE 0 END) 
           * 100.0 / COUNT(*), 2) AS poor_query_percentage
FROM Queries
WHERE query_name IS NOT NULL
GROUP BY query_name;

20. Monthly Transactions I

#1193

Find number of transactions and amounts per month per country.

SELECT DATE_FORMAT(trans_date, '%Y-%m') AS month,
       country,
       COUNT(*) AS trans_count,
       SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) 
           AS approved_count,
       SUM(amount) AS trans_total_amount,
       SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) 
           AS approved_total_amount
FROM Transactions
GROUP BY month, country;

21. Immediate Food Delivery II

#1174

Find percentage of immediate orders among first orders.

SELECT ROUND(
    AVG(CASE WHEN order_date = customer_pref_delivery_date 
        THEN 1 ELSE 0 END) * 100, 2
) AS immediate_percentage
FROM Delivery
WHERE (customer_id, order_date) IN (
    SELECT customer_id, MIN(order_date)
    FROM Delivery
    GROUP BY customer_id
);

22. Game Play Analysis IV

#550

Find fraction of players who logged in the day after first login.

SELECT ROUND(
    COUNT(DISTINCT a2.player_id) 
    / COUNT(DISTINCT a1.player_id), 2
) AS fraction
FROM (
    SELECT player_id, MIN(event_date) AS first_login
    FROM Activity
    GROUP BY player_id
) a1
LEFT JOIN Activity a2 
  ON a1.player_id = a2.player_id
  AND DATEDIFF(a2.event_date, a1.first_login) = 1;

Sorting and Grouping

23. Number of Unique Subjects Taught by Each Teacher

#2356

Count unique subjects per teacher.

SELECT teacher_id, 
       COUNT(DISTINCT subject_id) AS cnt
FROM Teacher
GROUP BY teacher_id;

24. User Activity for the Past 30 Days I

#1141

Find daily active users in the past 30 days.

SELECT activity_date AS day, 
       COUNT(DISTINCT user_id) AS active_users
FROM Activity
WHERE activity_date BETWEEN 
    DATE_SUB('2019-07-27', INTERVAL 29 DAY) 
    AND '2019-07-27'
GROUP BY activity_date;

25. Product Sales Analysis III

#1070

Select product_id, first year sold, quantity, and price.

SELECT product_id, year AS first_year, quantity, price
FROM Sales
WHERE (product_id, year) IN (
    SELECT product_id, MIN(year)
    FROM Sales
    GROUP BY product_id
);

26. Classes More Than 5 Students

#596

Find classes with at least 5 students.

SELECT class
FROM Courses
GROUP BY class
HAVING COUNT(student) >= 5;

27. Find Followers Count

#1729

Count followers for each user.

SELECT user_id, 
       COUNT(DISTINCT follower_id) AS followers_count
FROM Followers
GROUP BY user_id
ORDER BY user_id;

28. Biggest Single Number

#619

Find largest number that appears only once.

SELECT MAX(num) AS num
FROM (
    SELECT num
    FROM MyNumbers
    GROUP BY num
    HAVING COUNT(num) = 1
) AS single_numbers;

29. Customers Who Bought All Products

#1045

Find customers who bought all products.

SELECT customer_id
FROM Customer
GROUP BY customer_id
HAVING COUNT(DISTINCT product_key) = (
    SELECT COUNT(*) FROM Product
);

Advanced Select and Joins

30. The Number of Employees Which Report to Each Employee

#1731

Report employee info for those who have reports.

SELECT e1.employee_id, e1.name, 
       COUNT(e2.employee_id) AS reports_count,
       ROUND(AVG(e2.age)) AS average_age
FROM Employees e1
JOIN Employees e2 ON e1.employee_id = e2.reports_to
GROUP BY e1.employee_id, e1.name
ORDER BY e1.employee_id;

31. Primary Department for Each Employee

#1789

Report primary department for each employee.

SELECT employee_id, department_id
FROM Employee
WHERE primary_flag = 'Y'
   OR employee_id IN (
       SELECT employee_id
       FROM Employee
       GROUP BY employee_id
       HAVING COUNT(*) = 1
   );

32. Triangle Judgement

#610

Check if three lengths can form a triangle.

SELECT x, y, z,
       CASE 
           WHEN x + y > z AND x + z > y AND y + z > x 
           THEN 'Yes'
           ELSE 'No'
       END AS triangle
FROM Triangle;

33. Consecutive Numbers

#180

Find numbers that appear at least three times consecutively.

SELECT DISTINCT l1.num AS ConsecutiveNums
FROM Logs l1
JOIN Logs l2 ON l1.id = l2.id - 1 AND l1.num = l2.num
JOIN Logs l3 ON l1.id = l3.id - 2 AND l1.num = l3.num;

34. Product Price at a Given Date

#1164

Find prices of all products on 2019-08-16.

SELECT product_id, new_price AS price
FROM Products
WHERE (product_id, change_date) IN (
    SELECT product_id, MAX(change_date)
    FROM Products
    WHERE change_date <= '2019-08-16'
    GROUP BY product_id
)
UNION
SELECT product_id, 10 AS price
FROM Products
WHERE product_id NOT IN (
    SELECT product_id
    FROM Products
    WHERE change_date <= '2019-08-16'
);

35. Last Person to Fit in the Bus

#1204

Find last person to fit without exceeding 1000 kg.

SELECT person_name
FROM (
    SELECT person_name, 
           SUM(weight) OVER (ORDER BY turn) AS cumulative_weight
    FROM Queue
) AS q
WHERE cumulative_weight <= 1000
ORDER BY cumulative_weight DESC
LIMIT 1;

36. Count Salary Categories

#1907

Count accounts in each salary category.

SELECT 'Low Salary' AS category, 
       SUM(CASE WHEN income < 20000 THEN 1 ELSE 0 END) 
       AS accounts_count
FROM Accounts
UNION
SELECT 'Average Salary' AS category,
       SUM(CASE WHEN income BETWEEN 20000 AND 50000 
           THEN 1 ELSE 0 END) AS accounts_count
FROM Accounts
UNION
SELECT 'High Salary' AS category,
       SUM(CASE WHEN income > 50000 THEN 1 ELSE 0 END) 
       AS accounts_count
FROM Accounts;

Subqueries

37. Employees Whose Manager Left the Company

#1978

Find employees with salary < 30000 whose manager left.

SELECT employee_id
FROM Employees
WHERE salary < 30000
  AND manager_id NOT IN (
      SELECT employee_id FROM Employees
  )
ORDER BY employee_id;

38. Exchange Seats

#626

Swap seat IDs of consecutive students.

SELECT id,
       CASE 
           WHEN id % 2 = 1 AND id = (SELECT MAX(id) FROM Seat) 
               THEN student
           WHEN id % 2 = 1 
               THEN LEAD(student) OVER (ORDER BY id)
           ELSE LAG(student) OVER (ORDER BY id)
       END AS student
FROM Seat;

39. Movie Rating

#1341

Find user with most ratings and highest-rated movie in Feb 2020.

(SELECT u.name AS results
 FROM MovieRating mr
 JOIN Users u ON mr.user_id = u.user_id
 GROUP BY u.name
 ORDER BY COUNT(*) DESC, u.name
 LIMIT 1)
UNION ALL
(SELECT m.title AS results
 FROM MovieRating mr
 JOIN Movies m ON mr.movie_id = m.movie_id
 WHERE DATE_FORMAT(mr.created_at, '%Y-%m') = '2020-02'
 GROUP BY m.title
 ORDER BY AVG(mr.rating) DESC, m.title
 LIMIT 1);

40. Restaurant Growth

#1321

Calculate 7-day moving average of customer amounts.

SELECT visited_on,
       amount,
       ROUND(amount / 7, 2) AS average_amount
FROM (
    SELECT DISTINCT visited_on,
           SUM(amount) OVER (
               ORDER BY visited_on 
               RANGE BETWEEN INTERVAL 6 DAY PRECEDING 
               AND CURRENT ROW
           ) AS amount,
           MIN(visited_on) OVER () AS first_date
    FROM Customer
) t
WHERE visited_on >= DATE_ADD(first_date, INTERVAL 6 DAY);

41. Friend Requests II: Who Has the Most Friends

#602

Find person with most friends.

SELECT id, COUNT(*) AS num
FROM (
    SELECT requester_id AS id FROM RequestAccepted
    UNION ALL
    SELECT accepter_id AS id FROM RequestAccepted
) AS friends
GROUP BY id
ORDER BY num DESC
LIMIT 1;

42. Investments in 2016

#585

Find sum of investments for specific conditions.

SELECT ROUND(SUM(tiv_2016), 2) AS tiv_2016
FROM Insurance
WHERE tiv_2015 IN (
    SELECT tiv_2015
    FROM Insurance
    GROUP BY tiv_2015
    HAVING COUNT(*) > 1
)
AND (lat, lon) IN (
    SELECT lat, lon
    FROM Insurance
    GROUP BY lat, lon
    HAVING COUNT(*) = 1
);

43. Department Top Three Salaries

#185

Find top 3 salaries in each department.

SELECT d.name AS Department,
       e.name AS Employee,
       e.salary AS Salary
FROM Employee e
JOIN Department d ON e.departmentId = d.id
WHERE (
    SELECT COUNT(DISTINCT e2.salary)
    FROM Employee e2
    WHERE e2.departmentId = e.departmentId
      AND e2.salary >= e.salary
) <= 3;

Advanced String Functions / Regex

44. Fix Names in a Table

#1667

Fix names to have first letter capitalized.

SELECT user_id,
       CONCAT(UPPER(SUBSTRING(name, 1, 1)), 
              LOWER(SUBSTRING(name, 2))) AS name
FROM Users
ORDER BY user_id;

45. Patients With a Condition

#1527

Find patients with Type I Diabetes (DIAB1).

SELECT patient_id, patient_name, conditions
FROM Patients
WHERE conditions LIKE 'DIAB1%' 
   OR conditions LIKE '% DIAB1%';

46. Delete Duplicate Emails

#196

Delete duplicate emails keeping lowest id.

DELETE p1
FROM Person p1
JOIN Person p2 
  ON p1.email = p2.email 
  AND p1.id > p2.id;

47. Second Highest Salary

#176

Find second highest salary.

SELECT (
    SELECT DISTINCT salary
    FROM Employee
    ORDER BY salary DESC
    LIMIT 1 OFFSET 1
) AS SecondHighestSalary;

48. Group Sold Products By The Date

#1484

Group products sold per day.

SELECT sell_date,
       COUNT(DISTINCT product) AS num_sold,
       GROUP_CONCAT(DISTINCT product ORDER BY product) 
           AS products
FROM Activities
GROUP BY sell_date
ORDER BY sell_date;

49. List the Products Ordered in a Period

#1327

Find products with >= 100 units ordered in Feb 2020.

SELECT p.product_name, 
       SUM(o.unit) AS unit
FROM Products p
JOIN Orders o ON p.product_id = o.product_id
WHERE DATE_FORMAT(o.order_date, '%Y-%m') = '2020-02'
GROUP BY p.product_name
HAVING SUM(o.unit) >= 100;

50. Find Users With Valid E-Mails

#1517

Find users with valid LeetCode emails.

SELECT *
FROM Users
WHERE mail REGEXP '^[A-Za-z][A-Za-z0-9_.-]*@leetcode\\.com;

📚 Summary

These 50 problems cover essential SQL concepts including:

  • Basic SELECT statements and filtering
  • JOIN operations (INNER, LEFT, CROSS)
  • Aggregate functions (COUNT, SUM, AVG, MAX, MIN)
  • GROUP BY and HAVING clauses
  • Window functions (ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG)
  • Subqueries and CTEs
  • String manipulation and REGEX
  • Date/Time functions
  • CASE statements
  • UNION operations

💡 Practice these problems to build strong SQL fundamentals for technical interviews!

LeetCode Top SQL 50 Complete Solutions Guide

Created with ❤️ for SQL learners

Advertisement

300×250 Medium Rectangle

Leave a Reply

Your email address will not be published. Required fields are marked *