SQL Window Functions
debt(d7/e3/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). No detection_hints.tools are specified for this term. The common mistakes — omitting ORDER BY, misusing PARTITION BY vs GROUP BY, filtering on window function aliases in WHERE — produce no compile or syntax errors and typically no runtime error; they silently return wrong or non-deterministic results that only careful query review or data-validation testing will catch.
Closest to 'simple parameterised fix' (e3). The common mistakes each require targeted but straightforward fixes: adding ORDER BY inside OVER, swapping PARTITION BY for GROUP BY or restructuring the query, or wrapping in a subquery/CTE to allow WHERE filtering. These are local SQL-level rewrites, not multi-file refactors, but they go slightly beyond a single-line patch.
Closest to 'localised tax' (b3). Window function misuse is confined to the specific queries where they appear. The rest of the codebase is unaffected; fixing or learning the correct pattern only taxes the developer working on those particular reporting or analytics queries.
Closest to 'serious trap' (t7). The canonical misconception — that window functions reduce rows like aggregates do — directly contradicts how GROUP BY aggregates work, which is the closest familiar concept. Developers used to GROUP BY + aggregate naturally expect PARTITION BY + aggregate to collapse rows, but every input row is preserved. This contradicts a deeply ingrained mental model and is a documented, recurring source of incorrect query results.
TL;DR
Explanation
Unlike GROUP BY aggregates which reduce multiple rows to one, window functions operate over a defined frame of rows (the window) and return a value for every input row. The OVER clause defines the window via PARTITION BY (grouping), ORDER BY (row order within partition), and an optional ROWS/RANGE frame. Common functions include ROW_NUMBER (unique sequential rank), RANK/DENSE_RANK (tied ranks), LAG/LEAD (access previous/next row), and aggregate functions like SUM, AVG, MAX applied as running calculations. Window functions execute after WHERE and GROUP BY but before ORDER BY and LIMIT, making them composable with other clauses. In PHP applications they eliminate the need for multiple round trips or application-side sorting and ranking logic.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Omitting ORDER BY inside OVER for RANK or ROW_NUMBER — the result is non-deterministic.
- Using PARTITION BY when GROUP BY is intended — window functions do not reduce rows, so counts stay per-row.
- Trying to filter on a window function alias in WHERE — use a subquery or CTE; window functions are not available in WHERE.
Avoid When
- Avoid window functions when a simple GROUP BY aggregate answers the question — window functions have higher planning cost.
- Do not use them on tables without an appropriate index on the PARTITION BY and ORDER BY columns — the sort cost dominates.
When To Use
- Use ROW_NUMBER or RANK when you need per-partition rankings without losing the underlying rows (top N per category).
- Use LAG/LEAD to compare a row with its predecessor or successor in a time series without a self-join.
- Use SUM/AVG OVER for running totals, moving averages, and cumulative distributions in reporting queries.
Code Examples
-- Application-side ranking: N+1 queries
$users = $db->query('SELECT * FROM users ORDER BY score DESC');
$rank = 1;
foreach ($users as $u) {
$u['rank'] = $rank++; // sequential but ignores ties
}
-- Single query with window function:
SELECT
id,
name,
score,
RANK() OVER (ORDER BY score DESC) AS rank,
SUM(score) OVER () AS total_score
FROM users;