SQL window functions with examples

SQL window functions perform a calculation across a set of rows related to the current row using the `OVER()` clause, without grouping the rows into one. `PARTITION BY` splits rows into groups, `ORDER BY` orders them inside the window, and functions like `ROW_NUMBER()`, `RANK()`, `LAG()`, `LEAD()` and running `SUM()` operate over that frame.

The OVER clause

Every window function ends with OVER (PARTITION BY ... ORDER BY ...). PARTITION BY is optional (whole result set if omitted); ORDER BY defines row order and, for aggregates, the running frame.

Deduplicate with ROW_NUMBER

A common pattern: assign ROW_NUMBER() OVER (PARTITION BY key ORDER BY ts) and keep rn = 1 to pick the first/latest row per key.

The OVER clause and what makes a window function different

A window function computes a value across a set of rows related to the current row, but unlike GROUP BY it does not collapse them — every input row stays in the output, with the calculated value attached. That is what makes it the right tool for running totals, per-group rankings, and comparisons against a group average. The OVER clause defines the window: PARTITION BY restarts the calculation per group, ORDER BY sequences rows inside it, and the frame clause narrows which rows contribute. SUM(sales) OVER (PARTITION BY region ORDER BY sale_date) gives a running total per region.

Frames, ranking functions and where they are allowed

ROWS BETWEEN counts physical rows and RANGE BETWEEN works on the ordering values, so ties are grouped together — a distinction that changes the answer whenever the order column has duplicates. ROWS BETWEEN 2 PRECEDING AND CURRENT ROW is a three-row rolling window. For ranking, ROW_NUMBER() is always unique, RANK() leaves gaps after ties and DENSE_RANK() does not; LAG() and LEAD() reach to the previous or next row for period-over-period comparisons. One rule trips people up constantly: window functions are evaluated after WHERE and GROUP BY, so you cannot filter on one in the same WHERE clause. Wrap the query in a CTE or subquery and filter outside it — which is exactly why top-N-per-group queries always have two levels.

Example (SQL)

SELECT
  region,
  sale_date,
  amount,
  ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date)      AS rn,
  SUM(amount)  OVER (PARTITION BY region ORDER BY sale_date)      AS running_total
FROM sales
ORDER BY region, sale_date;

Numbers rows per region and computes a per-region running total of amount ordered by date.

Run this example in the free online PySpark compiler

Frequently asked questions

What is a window function in SQL?

A function that computes a value over a window of rows related to the current row via OVER(), without collapsing the rows the way GROUP BY does.

What does PARTITION BY do in a window function?

It divides the result set into independent groups; the window function restarts for each partition, similar to GROUP BY but keeping all rows.

How do I get the latest row per group in SQL?

Use ROW_NUMBER() OVER (PARTITION BY group ORDER BY timestamp DESC) and filter to rn = 1.

Practice challenges

Open the free PySpark compiler · Data Engineering challenges · Data Engineering jobs