Lesson 8 / 10

Window Functions

A window function calculates across a set of rows related to the current row — without collapsing them into one summary row the way GROUP BY does. This is one of the most powerful, and most underused, features in SQL for anyone coming from a beginner-level background.

Ranking rows

SELECT name, course, score,
       RANK() OVER (PARTITION BY course ORDER BY score DESC) AS rank_in_course
FROM students;

PARTITION BY divides the rows into groups, just like GROUP BY would — but unlike GROUP BY, every individual row is still returned, each one now carrying its rank within its own group. This gives every student a rank within their own course, while still showing every single row, something a plain GROUP BY simply cannot do in one query.

Running totals

SELECT name, score,
       SUM(score) OVER (ORDER BY name) AS running_total
FROM students;

A running total, running average, or running count over an ordered sequence of rows is a classic window function use case — the kind of calculation that’s genuinely painful to write with plain GROUP BY and joins, but reads almost naturally once you know the OVER (...) syntax.

ROW_NUMBER vs RANK vs DENSE_RANK

SELECT name, score,
  ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num,
  RANK()       OVER (ORDER BY score DESC) AS rank_num,
  DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank_num
FROM students;

ROW_NUMBER() always gives unique numbers, even for tied scores; RANK() gives tied rows the same number and then skips the next rank (1, 1, 3); DENSE_RANK() gives ties the same number without skipping (1, 1, 2). Pick based on whether gaps in the ranking should be allowed for your specific use case.