Spelling Bee Standings

A school spelling bee wants a standings board. Contestants are ranked by points, highest first. Contestants with equal points share a standing, and the next lower score gets the next consecutive standing: no numbers are skipped after a tie (for example 1, 2, 2, 3).

Return contestant, points and standing for every contestant. Order by points descending, then by contestant name ascending. If there are no contestants, return no rows.

Tables

bee_results — One row per contestant with their final score.

ColumnTypeDescription
contestant (key)TEXTContestant name (unique)
pointsINTEGERTotal points earned in the final round, 0 or more

Example

bee_results

contestantpoints
Amara42
Bilal37
Carmen42
Dmitri29
Esi37
Farid45
Greta29

Expected output

contestantpointsstanding
Farid451
Amara422
Carmen422
Bilal373
Esi373
Dmitri294
Greta294

Return the rows in exactly the order described. Your query also runs against hidden datasets with tricky edge cases.

SQL Path · Window Functions · problem 38 of 70 · SQLite

Ties share a standing and the next standing is not skipped: which ranking function behaves that way?
The ranking order (inside OVER) and the output order (the final ORDER BY) are separate; you need both.
Without a window function: a contestant's standing is the number of distinct scores greater than or equal to theirs.

The idea

SQL has three ranking functions, and they differ only in how they treat ties. ROW_NUMBER never ties. RANK ties but then skips (1, 2, 2, 4). DENSE_RANK ties and continues with the next integer (1, 2, 2, 3), which is what the board asks for.

DENSE_RANK() OVER (ORDER BY points DESC) computes the standing. The window's ORDER BY only decides how standings are assigned; it does not sort the result, so the query still needs its own ORDER BY points DESC, contestant. The name is the tie-breaker that makes the output order fully defined.

The alternative shows what dense ranking means: a contestant's standing is how many distinct scores are at least as high as theirs. Dropping DISTINCT there would reproduce RANK-style gaps, shifted by the ties.

Solution

SELECT
  contestant,
  points,
  DENSE_RANK() OVER (ORDER BY points DESC) AS standing
FROM bee_results
ORDER BY points DESC, contestant;

Another way

SELECT
  b.contestant,
  b.points,
  (SELECT COUNT(DISTINCT o.points)
   FROM bee_results AS o
   WHERE o.points >= b.points) AS standing
FROM bee_results AS b
ORDER BY b.points DESC, b.contestant;

Why common answers fail

RANK leaves gaps after a tie (1, 2, 2, 4), but the board needs consecutive standings.

SELECT contestant, points, RANK() OVER (ORDER BY points DESC) AS standing
FROM bee_results ORDER BY points DESC, contestant;

ROW_NUMBER gives tied contestants different standings.

SELECT contestant, points, ROW_NUMBER() OVER (ORDER BY points DESC, contestant) AS standing
FROM bee_results ORDER BY points DESC, contestant;

Ranks in ascending order, so the lowest score gets standing 1.

SELECT contestant, points, DENSE_RANK() OVER (ORDER BY points) AS standing
FROM bee_results ORDER BY points DESC, contestant;

What the interviewer is checking

A quick check that you know the difference between ROW_NUMBER, RANK and DENSE_RANK, and that window ordering is not result ordering.

Mistakes to avoid

  • Using RANK and getting gaps after ties.
  • Relying on the window ORDER BY to sort the output.
  • Forgetting DESC, so the lowest score ranks first.

Follow-ups to expect

  • Show standings per school (PARTITION BY school_id).
  • Return only contestants in the top 3 standings (filter the ranked result in an outer query).
  • What changes if points could be NULL for absent contestants? (Decide where NULLs sort; SQLite puts them first in ascending order, last in descending.)

In real work

Leaderboards, sales-league tables and "top N tiers" reports all rely on dense ranking so that ties do not create missing positions.

Practice next

Next Post Previous Post
No Comment
Add Comment
comment url