Window Functions
Window functions let you compute rankings, running totals, and neighbor comparisons per row without collapsing the result set. Interviewers lean on them heavily because they separate SQL users who can only GROUP BY from those who can solve real analytics problems like top-N per group in one query.
part ofSQLoverview, primer and where to startread it →on this pageshowhide
explore
- OVER Clause Anatomy4 questions
- Ranking Functions5 questions
- Frame Specification: ROWS, RANGE, GROUPS6 questions
- Named Windows: the WINDOW Clause4 questions
- Pattern: Top-N per Group5 questions
- Pattern: Deduplication with ROW_NUMBER5 questions
- Pattern: Gaps and Islands5 questions
- Window Functions vs GROUP BY5 questions
- AI & Data Scientistrole
- AI Engineerrole
- BI Analystrole
- Backend Developerrole
- Cyber Security Expertrole
- Data Analystrole
- Data Engineerrole
- Full Stack Developerrole
- Java Backend Developerrole
- Java SDETrole
- Kotlin Backend Developerrole
- MLOps Engineerrole
- Machine Learning Engineerrole
- PostgreSQL DBArole
- QA Engineerrole
- SQLskill
questions
page 2 of 2How do you compute a 3-day moving average of daily revenue with a window function?
basics
~20 sUse AVG(revenue) OVER (ORDER BY day ROWS BETWEEN 2 PRECEDING AND CURRENT ROW). For each row the frame holds that row plus the two before it, so the average slides down the ordered rows, one row at a time.
How do you deduplicate a table whose rows are byte-identical and that has no unique column?
basics
~20 sROW_NUMBER can still number identical rows, but no portable DELETE can target one copy, because any predicate matching a loser matches the survivor too. Rebuild the table from the rn = 1 set and swap it in.
In a ROW_NUMBER dedup partitioned by email, what happens to rows whose email is NULL?
basics
~20 sThey all land in one partition. PARTITION BY groups NULLs together as peers rather than using = comparison, so every NULL-email row after the first is numbered above 1 and a delete of rn > 1 wipes out unrelated records.
What does RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND CURRENT ROW define as a frame?
basics
~20 sA value-based frame: every row whose ORDER BY date lies within seven days before the current row's date, through the current row and its peers. Both endpoints are inclusive, and days with no rows simply contribute nothing.
How do you group event rows into sessions that break after 30 minutes of inactivity?
basics
~20 sCompare each row with the previous one using LAG(); emit 1 when the elapsed time exceeds the threshold and 0 otherwise, then take a running SUM() of that flag in the same order. The cumulative sum is a session id you can GROUP BY.
A report repeats the same PARTITION BY and ORDER BY across eight window columns with different frames — how do you restructure it?
basics
~20 sDefine one named window carrying the shared PARTITION BY and ORDER BY and no frame, then let each column refine it with OVER (w ROWS ...). The partition key then lives in one place, and the base must stay frame-free to remain refinable.
Does ORDER BY inside OVER () also determine the order of the query's output rows?
basics
~20 sNo. The ORDER BY inside an OVER clause only sequences rows within each partition so the window function can be computed; it makes no promise about the order rows are returned in. Only a query-level ORDER BY guarantees output order.
NTILE(10) puts identical spend values in different deciles and boundaries move as data grows - how do you get stable segments?
basics
~20 sNTILE(10) guarantees equal-sized buckets, not equal value ranges, so identical amounts can fall either side of a boundary and cut-points drift as the population changes. For segments that depend on the value itself, bucket on explicit cut-points with a CASE expression.
How do you return the top 3 products per category by total revenue across many order lines?
basics
~20 sAggregate first, rank second. Sum revenue per category and product with GROUP BY, then apply ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY revenue DESC) over that grouped result, and filter rn <= 3 one level further out.
A share-of-total column using SUM() OVER () shows shares of a filtered subset, not the company total — why?
basics
~20 sBecause WHERE is applied before window functions: the window only ever sees rows that survived the filter, so its total covers the filtered subset. To divide by an unfiltered total, compute the window in an inner query over all rows and filter outside it.
How do you return each transaction with both a month-to-date and a lifetime running balance?
basics
~20 sPut two windowed SUMs in one SELECT: one partitioned by account plus the year and month of the transaction, one partitioned by account alone, both ordered by transaction time. Each OVER clause is evaluated independently over the same rows.
In SQL, what is the gaps-and-islands problem, and what counts as an island?
basics
~20 sGaps and islands names a family of SQL problems over an ordered column: islands are maximal runs of consecutive values, gaps are the stretches missing between them. The work is inventing a group key per run.
Where does the WINDOW clause appear in a SELECT statement, and what is a named window's scope?
basics
~20 sThe WINDOW clause sits between HAVING and ORDER BY. A named window is scoped to the query block that defines it, and within that block OVER w can be used in the SELECT list and in the query's ORDER BY.
What is the difference between PERCENT_RANK() and CUME_DIST() for tied rows?
basics
~20 sBoth give every tied row the same value. PERCENT_RANK() is (RANK() - 1) / (rows - 1), so the first row is always 0. CUME_DIST() is the fraction of rows at or before the tie group, so the last row is always 1.
What does a QUALIFY clause do in a top-N-per-group query, in dialects that offer it?
basics
~20 sQUALIFY filters on window function results the way HAVING filters on aggregates, so you can write the rank predicate in the same query instead of wrapping it. It is a dialect extension, not part of the ISO SQL standard.
What do EXCLUDE CURRENT ROW and EXCLUDE TIES do in a window frame clause?
basics
~20 sEXCLUDE CURRENT ROW removes just the current row from the frame that was computed; EXCLUDE TIES removes its peers but keeps the current row. EXCLUDE GROUP removes both, and EXCLUDE NO OTHERS, the default, removes nothing.
What does GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING count in a window frame?
basics
~20 sPeer groups, not rows or values. The frame covers all rows tied with the current row, plus every row of the one tied group before it and the one tied group after it, however many rows each group contains.
How do you carry the last non-NULL value forward when IGNORE NULLS is unavailable?
basics
~20 sBuild a group id with COUNT(reading) OVER (ORDER BY ts), which stays constant across a run of NULLs, then take FIRST_VALUE(reading) OVER (PARTITION BY that id ORDER BY ts). Rows before the first value stay NULL.
Why does COUNT(DISTINCT user_id) OVER (PARTITION BY month) fail on most engines?
basics
~20 sBecause DISTINCT is not supported in the windowed form of an aggregate. PostgreSQL and SQL Server reject it outright, and MySQL does not support it either. Compute the distinct count in a grouped step and attach it to the detail rows instead.
showing 31–49 of 49