Skip to main content

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples in this guide work on VillageSQL. Install Now →
Window functions compute values across a set of rows related to the current row — without collapsing those rows into a single output row the way GROUP BY does. They enable analytics queries that previously required subqueries or application-layer processing.

How Window Functions Differ from GROUP BY

The second query returns one row per order, with each row also showing the total for that customer. GROUP BY can’t do this — it removes the individual rows.

The OVER Clause

Every window function uses an OVER clause that defines the window — the set of rows to compute over.
An empty OVER() means the window is the entire result set.

Ranking Functions

Example output:

PARTITION BY: Per-Group Rankings

Add PARTITION BY to rank within groups instead of across the whole result set:
To get each customer’s most recent order:

LAG and LEAD: Accessing Adjacent Rows

LAG accesses a previous row; LEAD accesses a following row — without a self-join.
Both functions accept an optional offset (default 1) and a default value for when no adjacent row exists:

Running Totals and Moving Averages

Use ROWS BETWEEN to define a frame — the subset of rows to include in the calculation.
Common frame specifications:

Frequently Asked Questions

Can I filter on a window function result in a WHERE clause?

No — window functions are evaluated after WHERE. To filter on a window function result, wrap the query in a subquery or CTE:

What’s the difference between ROWS and RANGE in the frame clause?

ROWS counts physical rows. RANGE groups rows with the same ORDER BY value together. For most use cases (running totals, moving averages), ROWS gives the expected behavior. RANGE can produce surprising results when there are ties in the order column.

Do window functions work with indexes?

Window functions don’t use indexes for the window computation itself, but the query can still use indexes for the WHERE clause to reduce the rows being processed. Complex window queries benefit from Reading EXPLAIN in MySQL to understand the execution plan.

Troubleshooting

See also