Databases 10 min read

Unlocking LeetCode’s Hardest SQL Problem with Window Functions

This article examines LeetCode problem 185 – the hardest SQL challenge – by preparing the Employee and Department tables, presenting two solution approaches (a subquery and a window‑function version), benchmarking their performance on large test data, and explaining why window functions are the superior choice in MySQL 8+.

Aikesheng Open Source Community
Aikesheng Open Source Community
Aikesheng Open Source Community
Unlocking LeetCode’s Hardest SQL Problem with Window Functions

LeetCode’s Hardest SQL Question?

Frequent LeetCode users will recognize Problem 185: Department Top Three Salaries , the only hard‑difficulty database problem on the platform, with over 900,000 submissions and a 58.3% acceptance rate.

Preparing the Tables and Sample Data

CREATE TABLE IF NOT EXISTS Employee (
  id INT,
  name VARCHAR(255),
  salary INT,
  departmentId INT
);
CREATE TABLE IF NOT EXISTS Department (
  id INT,
  name VARCHAR(255)
);
TRUNCATE TABLE Employee;
INSERT INTO Employee (id, name, salary, departmentId) VALUES
  (1, 'Joe', 85000, 1),
  (2, 'Henry', 80000, 2),
  (3, 'Sam', 60000, 2),
  (4, 'Max', 90000, 1),
  (5, 'Janet', 69000, 1),
  (6, 'Randy', 85000, 1),
  (7, 'Will', 70000, 1);
TRUNCATE TABLE Department;
INSERT INTO Department (id, name) VALUES (1, 'IT'), (2, 'Sales');

The Employee table stores each employee’s ID, name, salary, and department ID, while the Department table stores department IDs and names.

Problem Statement

For each department, retrieve all employees whose salaries rank among the top three distinct salaries in that department. The result can be returned in any order.

Example Input and Output

Input: the Employee and Department tables shown above.

Output:

Department | Employee | Salary
-----------+----------+--------
IT         | Max      | 90000
IT         | Joe      | 85000
IT         | Randy    | 85000
IT         | Will     | 70000
Sales      | Henry    | 80000
Sales      | Sam      | 60000

Official Answer Comparison

Solution 1: Subquery

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

This approach uses a correlated subquery to count how many distinct higher salaries exist for each employee within the same department; if fewer than three, the employee is kept.

Solution 2: Window Function

WITH employee_department AS (
  SELECT d.id,
         d.name AS Department,
         e.salary AS Salary,
         e.name AS Employee,
         DENSE_RANK() OVER (PARTITION BY d.id ORDER BY e.salary DESC) AS rnk
  FROM Department d
  JOIN Employee e ON d.id = e.departmentId
)
SELECT Department, Employee, Salary
FROM employee_department
WHERE rnk <= 3;

The DENSE_RANK() window function ranks salaries per department and directly filters the top three.

Performance Testing

We generated a larger test set using a stored procedure that creates 10 departments, each with 1,000 employees (10,000 rows total).

DELIMITER $$
CREATE PROCEDURE generate_test_data()
BEGIN
  DECLARE i INT DEFAULT 1;
  DECLARE j INT DEFAULT 1;
  DECLARE emp_id INT DEFAULT 1;
  WHILE i <= 10 DO
    INSERT INTO Department (id, name) VALUES (i, CONCAT('Dept_', i));
    SET j = 1;
    WHILE j <= 1000 DO
      INSERT INTO Employee (id, name, salary, departmentId)
      VALUES (emp_id, CONCAT('Employee_', emp_id), FLOOR(3000 + RAND() * 7000), i);
      SET emp_id = emp_id + 1;
      SET j = j + 1;
    END WHILE;
    SET i = i + 1;
  END WHILE;
END$$
DELIMITER ;
CALL generate_test_data();

Running the two queries on this dataset showed a dramatic difference: the window‑function version completed in sub‑millisecond time, while the subquery version took over five seconds.

Performance comparison chart
Performance comparison chart

Why Use Window Functions?

Avoid repeated scans and calculations: Traditional subqueries often require multiple passes over the data, causing performance bottlenecks; window functions compute results in a single scan.

Reduce intermediate results and temporary tables: Subqueries may generate large temporary tables, increasing memory and disk usage; window functions operate directly on the result set.

Eliminate unnecessary materialization: When the same PARTITION BY and ORDER BY are used, window functions share computation, avoiding duplicate work.

Conclusion and Recommendation

When using MySQL 8.0+ or any database that supports window functions, prefer the window‑function solution for this problem; it is both simpler and dramatically faster.

PerformanceSQLMySQLLeetCodeWindow Functions
Aikesheng Open Source Community
Written by

Aikesheng Open Source Community

The Aikesheng Open Source Community provides stable, enterprise‑grade MySQL open‑source tools and services, releases a premium open‑source component each year (1024), and continuously operates and maintains them.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.