
Dan Patiño
AI Strategy & Innovation at Coderhouse
Data
SQL window functions are calculations that look across a set of rows related to the current row, called a window, and return a result for every row without collapsing them into groups. Where GROUP BY turns many rows into one summary row, a window function keeps every row and adds a new column next to it: a running total, a rank, the previous month’s value, or a moving average.
Why it matters now: most analytics questions are comparisons. How does this month compare with last month? Which product ranks first in each region? What is the seven-day average of signups? Before window functions, analysts answered these with self-joins and subqueries that were slow to write and easy to get wrong. Today every major database and cloud warehouse supports them, and they show up in almost every data analyst interview and in most production dashboards.
How a window function works
Every window function uses the OVER() clause, which tells the database which rows belong to the window. Inside it you can combine three parts:
PARTITION BY splits the rows into independent groups, such as one window per customer or per region. The calculation restarts for each partition.
ORDER BY sorts the rows inside each partition, which matters for rankings, running totals, and anything that refers to a “previous” or “next” row.
A frame clause (
ROWS BETWEEN ...orRANGE BETWEEN ...) narrows the window to a slice around the current row, for example the six rows before it plus the current one.
A simple example ranks orders by value inside each country:
SELECT country, order_id, amount, RANK() OVER (PARTITION BY country ORDER BY amount DESC) AS rank_in_country FROM orders;
Every order stays in the result, and each one gets its position within its own country. The PostgreSQL tutorial on window functions is one of the clearest official introductions to this behavior.
The main families of window functions
Ranking functions
ROW_NUMBER(), RANK(), DENSE_RANK(), and NTILE() assign positions. ROW_NUMBER() always gives unique numbers, RANK() leaves gaps after ties, and DENSE_RANK() does not. A classic use is “top N per group”: number the rows inside each partition, then keep only those with a number of three or lower.
Offset functions
LAG() and LEAD() read a value from a previous or following row, while FIRST_VALUE() and LAST_VALUE() read the edges of the window. They make period-over-period comparisons, such as month-over-month revenue growth, a single readable query.
Aggregate functions used as windows
Familiar aggregates like SUM(), AVG(), COUNT(), MIN(), and MAX() become window functions when you add OVER(). With an ORDER BY they produce running totals; with a frame such as ROWS BETWEEN 6 PRECEDING AND CURRENT ROW they produce moving averages. You can find the complete list in the PostgreSQL window functions reference and the BigQuery window function calls documentation.
Everyday use cases for analysts
Running totals and year-to-date figures for revenue, signups, or tickets closed.
Moving averages that smooth noisy daily data before it goes on a chart.
Period-over-period change with
LAG(), such as week-over-week growth.Top N per category, such as the three best-selling products in each store.
Deduplication: keep only the latest record per customer by numbering rows by timestamp and filtering to the first one.
Share of total: divide each row by
SUM(amount) OVER (PARTITION BY region)to get its percentage within the region.Retention and cohort work, where you find each user’s first activity date with
MIN() OVER (PARTITION BY user_id). Our guide to what cohort analysis is shows where that step fits.
Window functions vs GROUP BY
The two are complementary. Use GROUP BY when you want one row per group, such as total sales per country. Use a window function when you need the detail and the summary side by side, such as each order next to its country’s total. A useful rule of thumb: if you are about to join a table to an aggregated version of itself, a window function is usually simpler and faster.
Common mistakes
Filtering on a window result in WHERE. Window functions are calculated after
WHERE, so you cannot filter on them there. Wrap the query in a subquery or CTE, or useQUALIFYin warehouses that support it, such as BigQuery and Snowflake.Forgetting ORDER BY inside OVER. Without it, running totals and
LAG()results depend on whatever order the database happens to use.Surprises from the default frame. When you add
ORDER BY, many databases default to a frame that ends at the current row, soLAST_VALUE()often returns the current row instead of the true last one. Specify the frame explicitly.Ties in rankings. Decide whether ties should share a rank (
RANK,DENSE_RANK) or break arbitrarily (ROW_NUMBER), and add a tiebreaker column if results must be repeatable.Huge partitions. Ordering billions of rows in a single partition is expensive. Partition sensibly and filter early.
How window functions fit in the modern data stack
Window functions are a building block for analytics engineering. Transformation tools run them inside the warehouse to produce clean, reusable tables, as we explain in what dbt is. They also matter for AI: when an assistant generates SQL from a plain-English question, analysts still need to read and check window logic, since a wrong partition or frame produces numbers that look plausible but are off.
FAQ
Are window functions the same in every database?
The core syntax comes from the SQL standard and works in PostgreSQL, MySQL 8+, SQL Server, Oracle, SQLite, BigQuery, Snowflake, and others. Extras such as QUALIFY or specific frame options vary, so check your database’s documentation.
Do window functions slow down queries?
They require sorting within partitions, which has a cost, but they are usually faster than the self-joins and correlated subqueries they replace.
When should I learn them?
Right after you are comfortable with SELECT, JOIN, and GROUP BY. They are often the step that moves someone from basic SQL to analyst-level SQL.
Ready to write analyst-level SQL and put it to work with AI? Explore these Coderhouse courses:
Data Analytics Course — master SQL, data cleaning, and dashboards with real business datasets.
AI Engineering Course — build AI applications that query and reason over your data.
I'm Dan Patiño, head of AI Strategy & Innovation at Coderhouse. My day-to-day work involves merging the tactical management of e-commerce (CRO, Email Marketing and SEO) with the development of disruptive solutions. I specialize in building internal AI-powered apps to automate tasks and boost innovation within the team. I firmly believe that technology is strategy's best ally. To dive deeper into my professional journey, I'll be waiting for you on my LinkedIn profile.