Skip to content

Window Functions (OVER, PARTITION BY)

Why window functions

Window functions let you compute metrics across related rows while keeping each row.

Common uses:

  • Rank customers by revenue
  • Running totals over time
  • Moving averages

ROW_NUMBER and RANK

Rank orders by amount per user
SELECT
  user_id,
  order_id,
  amount,
  ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rn
FROM orders;
Rank orders by amount per user
SELECT
  user_id,
  order_id,
  amount,
  ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rn
FROM orders;

Running total

Running revenue by date
SELECT
  order_date,
  daily_revenue,
  SUM(daily_revenue) OVER (ORDER BY order_date) AS running_revenue
FROM (
  SELECT
    DATE(order_ts) AS order_date,
    SUM(amount) AS daily_revenue
  FROM orders
  GROUP BY DATE(order_ts)
) t
ORDER BY order_date;
Running revenue by date
SELECT
  order_date,
  daily_revenue,
  SUM(daily_revenue) OVER (ORDER BY order_date) AS running_revenue
FROM (
  SELECT
    DATE(order_ts) AS order_date,
    SUM(amount) AS daily_revenue
  FROM orders
  GROUP BY DATE(order_ts)
) t
ORDER BY order_date;

PARTITION BY

  • Splits data into groups
  • Window function works within each group

Example: running revenue by country.

Window functions vs GROUP BY

The key difference from GROUP BYGROUP BY: a window function does not collapse rows. Every input row stays in the result, but each row also gets a computed value based on the rows around it (its “window”).

diagram How OVER (PARTITION BY ...) works mermaid
PARTITION BY splits rows into windows; the function computes a value per row using only the rows in its own window.
sketch Partitions computed independently p5.js
Rows are grouped into colored partitions; RANK restarts at 1 inside each partition instead of continuing across the whole table.

🧪 Try It Yourself

Exercise 1 – ROW_NUMBER per partition

Exercise 2 – Running total with SUM() OVER

Exercise 3 – RANK vs ROW_NUMBER on ties

Next

CTEs (WITH) and Subqueries show you how to name and reuse the derived tables you’ve been building inline with subqueries so far.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did