SQL Ranking Functions Practice — 32 Challenges (10 Free)

"The top three products in each category", "the latest order per customer", "the second-highest salary": most ranking questions are one of these, and every one is a ranking function over a PARTITION BY, then a filter on the rank. These 32 challenges are every one in the bank whose reference solution ranks rows.

Find your weakest skill first →

ROW_NUMBER — exactly one row per position: 15 challenges (5 free)

Numbers rows 1, 2, 3 with no ties, even when two rows are equal. That is what you want for "the latest order per customer": ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY ordered_at DESC), then keep rank 1. Add a tie-breaker to the ORDER BY, or the row you keep is arbitrary.

Counted from the challenge bank, September 2026. Easy first, then Medium, then Hard.

Medium Free

Window Functions: ROW_NUMBER

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Medium Free

Most Recent Order Per Customer (ROW_NUMBER)

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Medium Free

Second-Highest Earner Per Department (ROW_NUMBER)

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Medium Free

Top 3 Merchants Per Category by Spend

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Medium Free

Busiest Merchants, and What a Tie Does to the Rank

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top Earner Per Department

Uses: SELECT Window Functions Subquery

Try it →
Hard Pro

RANK vs DENSE_RANK: Rating Gaps

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top-N Products per Category

Uses: SELECT CTE Window Functions

Try it →
Hard Pro

Median Salary Without PERCENTILE

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Pro

Deduplicate Orders with ROW_NUMBER

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Pro

Island Length Classification

Uses: SELECT CTE Window Functions

Try it →
Hard Pro

Earliest Movie per Genre

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Pro

First-to-Second Transaction Latency

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Pro

How Concentrated Is the Spend?

Uses: SELECT CTE Window Functions

Try it →
Hard Pro

Top 3 Spending Categories per Country

Uses: SELECT CTE Window Functions

Try it →

RANK and DENSE_RANK — when ties matter: 14 challenges (6 free)

Two salaries of 90,000 are both second. RANK then skips to fourth; DENSE_RANK goes to third. "The second-highest salary" is a DENSE_RANK question, and saying why out loud is half the interview answer.

Counted from the challenge bank, September 2026. Easy first, then Medium, then Hard.

Easy Free

Rank Everyone by Salary

Uses: SELECT Window Functions RANK

Try it →
Medium Free

RANK vs DENSE_RANK Side-by-Side

Uses: SELECT Window Functions RANK

Try it →
Medium Free

Top 3 Salary Tiers (DENSE_RANK)

Uses: SELECT Window Functions DENSE_RANK

Try it →
Medium Free

Busiest Merchants, and What a Tie Does to the Rank

Uses: SELECT Window Functions RANK

Try it →
Hard Free preview

Salary Rank Within Department

Uses: SELECT Window Functions ORDER BY

Try it →
Hard Free preview

Multi-CTE Revenue Pipeline

Uses: SELECT CTE JOIN

Try it →
Hard Pro

Nth Highest Salary per Department

Uses: SELECT Subquery Window Functions

Try it →
Hard Pro

Rank Movies by Rating

Uses: SELECT Window Functions ORDER BY

Try it →
Hard Pro

RANK vs DENSE_RANK: Rating Gaps

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top Spender per Membership Tier

Uses: SELECT CTE JOIN

Try it →
Hard Pro

Second Highest Salary per Department

Uses: SELECT Window Functions DENSE_RANK

Try it →
Hard Pro

Top 3 Banks Per State by Assets

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top 3 Sales Per Borough

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top 5 Torque Per Quality

Uses: SELECT Window Functions RANK

Try it →

Top-N per group — rank inside a partition, then filter: 19 challenges (5 free)

The ranking runs in a CTE or a subquery, because a window function cannot sit in WHERE. Then the outer query keeps rn <= N. This is the shape behind "top sellers by region" and "best month per product".

Counted from the challenge bank, September 2026. Easy first, then Medium, then Hard.

Medium Free

Window Functions: ROW_NUMBER

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Medium Free

Most Recent Order Per Customer (ROW_NUMBER)

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Medium Free

Second-Highest Earner Per Department (ROW_NUMBER)

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Medium Free

Top 3 Merchants Per Category by Spend

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Free preview

Salary Rank Within Department

Uses: SELECT Window Functions ORDER BY

Try it →
Hard Pro

Nth Highest Salary per Department

Uses: SELECT Subquery Window Functions

Try it →
Hard Pro

Rank Movies by Rating

Uses: SELECT Window Functions ORDER BY

Try it →
Hard Pro

Top Earner Per Department

Uses: SELECT Window Functions Subquery

Try it →
Hard Pro

RANK vs DENSE_RANK: Rating Gaps

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top-N Products per Category

Uses: SELECT CTE Window Functions

Try it →
Hard Pro

Deduplicate Orders with ROW_NUMBER

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Pro

Top Spender per Membership Tier

Uses: SELECT CTE JOIN

Try it →
Hard Pro

Second Highest Salary per Department

Uses: SELECT Window Functions DENSE_RANK

Try it →
Hard Pro

Earliest Movie per Genre

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Pro

Top 3 Banks Per State by Assets

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top 3 Sales Per Borough

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

Top 5 Torque Per Quality

Uses: SELECT Window Functions RANK

Try it →
Hard Pro

First-to-Second Transaction Latency

Uses: SELECT Window Functions ROW_NUMBER

Try it →
Hard Pro

Top 3 Spending Categories per Country

Uses: SELECT CTE Window Functions

Try it →

Where this shows up next

Once rows are ranked, the next questions are about neighbours and running sums: window functions cover LAG, LEAD and frames. The filter-after-ranking step is a CTE or a subquery, and the rows being ranked usually come out of a join.

Questions

What is the difference between RANK, DENSE_RANK and ROW_NUMBER?

ROW_NUMBER gives every row a distinct number, ties included. RANK gives tied rows the same number and then skips (1, 2, 2, 4). DENSE_RANK gives tied rows the same number without skipping (1, 2, 2, 3).

How do I get the top N rows per group in SQL?

Rank inside the group with ROW_NUMBER() or DENSE_RANK() OVER (PARTITION BY group ORDER BY metric DESC) in a CTE or subquery, then filter the rank in the outer query. A window function cannot be used directly in WHERE.