Window functions — keep the grain, rank the rows
A window function computes over a set of rows and hands the answer back to every row, so the result keeps its grain — the property that makes a keep-latest dedupe safe and a bare GROUP BY grain-changing. You find the duplicates first with one GROUP BY query, dedupe on the business key keeping the latest by event time, and learn when a window over the same key is a shuffle that can skew or spill.
At a glance
| When | Row counts are inflated and the fix must keep one row per key; A ranking or latest-per-key read has to stay at the row grain |
|---|---|
| Where | SQL |
| Why | Windows are the tool that computes over a set without changing the grain — which is why dedupe and rankings go through them. |
Learning objectives
- Keep the result grain intact — a window computes over a set without collapsing rows
- Find duplicate keys with one GROUP BY query before deduplicating
- Deduplicate on the business key, keeping the latest by event time
What you need
- A table with a business key and an event-time column
- [object Object]
- The local DuckDB from lesson 2 works for all the practice queries
Steps
- Review the failure modes first — the sql-review skill exists to catch functions that silently change grain, alongside fan-out joins, NULL-unsafe predicates, implicit casts, and non-deterministic ordering. (from skill-sql-review )
- State the grain of a result set in one sentence — a window keeps the row grain while computing over its partition, a GROUP BY changes it. (from skill-sql-review )
- Find the duplicate key first — identify the duplicate key and count duplicates per key. (from runbook-duplicate-records )
- Count duplicates per key with one query: SELECT k, count(*) c FROM t GROUP BY k HAVING count(*) > 1 ORDER BY c DESC LIMIT 20; (from runbook-duplicate-records )
- Deduplicate on the business key, keeping the latest by event time. (from runbook-duplicate-records )
- Treat the group-by (and any window over the same key) as a shuffle — key skew on a join or group-by key is the first cause to check. (from tutorial-spark-aggregations-windows )
- Spill to disk from an oversized partition — a window partition that gets too big is a known shuffle failure. (from runbook-spark-job-slow )
Check yourself
- The deduped table has one row per business key, and the GROUP BY duplicate count proves it.
- You can say in one sentence what the window preserved that a GROUP BY would have collapsed.
- The window's PARTITION BY key is the same key you checked for skew.
Worked example
Find the duplicate keys the window dedupe will remove — from runbook-duplicate-records
SELECT k, count(*) c FROM t GROUP BY k HAVING count(*) > 1 ORDER BY c DESC LIMIT 20;
SELECT min(dt), max(dt) FROM (SELECT dt, k, count(*) FROM t GROUP BY dt, k HAVING count(*)>1);
Sourced from
Security scan
Last sweep 2026-10-24: 0 finding(s), 0 marked as examples.
Common gotchas
- A window keeps the grain, a GROUP BY changes it — pick by the grain you owe the consumer.
- Dedupe on the business key, keeping the latest by event time — not by insertion order.
- A window over a skewed key is a shuffle with a hot partition — it can spill to disk.
Production considerations
- Keep the GROUP BY duplicate-count query next to the dedupe job as its check.
- Check the write mode before dedupe — append vs merge/overwrite decides what the rewrite touches.
Diagram
window functions and grain
|
|- GROUP BY --> new grain (one row per key)
|
|- window --> same grain, value computed over the partition
|
|- dedupe --> business key --> keep latest by event time
|
|- at scale --> window = shuffle --> skew / spill to disk
Registry stats
| Verification | community · Oct 23, 2026 |
|---|---|
| Completeness | 81 |
| Trust multiplier | ×1.25 |
| Composite | 34.15 · adequate |
| Freshness | 1 days since last source check |
| Difficulty | intermediate |
| Version | 0.1.0 |
| License | CC-BY-4.0 |
| Security flags | none |
Did this solve your problem?
Window functions — keep the grain, rank the rows