Question presented to candidate:
"We have an employees table with dept and salary. Give me the two highest-paid people in every department, with their names and salaries, as normal rows. What happens when two people tie for second place?"
What a strong answer should cover:
- Why
GROUP BY deptwithMAX(salary)is the wrong tool: it collapses each department to one row and loses the names; a window function keeps every row and adds a number to it RANK() OVER (PARTITION BY dept ORDER BY salary DESC)numbers each department separately, then an outer query (CTE or derived table) filtersWHERE rnk <= 2- Why the filter cannot go in the same
WHERE: window functions are computed afterWHERE, so both SQLite and PostgreSQL reject it - Ties:
RANK() <= 2can return more than two rows per group,ROW_NUMBER()returns exactly two (add a tiebreaker),DENSE_RANK() <= 2returns the top two distinct salaries - Alternatives and cost: a correlated
COUNT(*)subquery (works without window functions),LATERAL ... LIMITwith an index for few rows per group,QUALIFYon engines that have it; PostgreSQL 15+ can stop the window early (Run Condition)
Clarifying questions expected:
- If two people tie for second place, should both appear, or exactly two rows per department?
- Do departments with fewer than two people still appear (yes, with whoever they have)?
- How big is the table and is there an index on
(dept, salary)— is this a report or a hot API path?
Code / implementation expected: Yes — a ranked CTE filtered in an outer query, and an explanation of how the choice of ranking function changes the result on ties.
Schema used by the examples: