lesson 79 Warehouse & reporting projects · advanced
Product validity with LEAD & half-open intervals
Define product validity using the next change date.
the idea
LEAD finds the next version start. Use [valid_from,valid_to) so a change date belongs to exactly one version; NULL end means current. This lab has unique starts per product. Latest-only output discards history; an as-of join needs all versions.
tables in this lesson
The challenges use this data. Each column shows its type underneath; → marks a link to another table.
product_versions5 columns · 4 rows
| version_idinteger · key | product_idtext | nametext | costreal | valid_fromtext |
|---|---|---|---|---|
| 1 | P01 | Notebook | 8 | 2024-01-01 |
| 2 | P01 | Notebook | 9 | 2025-02-01 |
| 3 | P02 | Desk lamp | 30 | 2024-01-01 |
| 4 | P02 | Desk lamp | 32 | 2025-03-01 |
all 4 rows
example
The idea in one query. Press Run to see what it returns; running examples never affects your progress.
SELECT version_id, product_id, valid_from, LEAD(valid_from) OVER(PARTITION BY product_id ORDER BY valid_from,version_id) AS valid_to FROM product_versions;
Watch for: Do not subtract a day from timestamp boundaries; half-open intervals avoid gaps and double matches.
build it step by step
Each step changes one thing. Run them in order and watch the result change.
Understand the source contract. Fictional extracts, load counts, invalid dates, versioned dimensions, refresh staging and a data catalog. The foundation project is latest-state; separate history and incremental labs demonstrate extensions.
step-1.sqlSELECT * FROM product_versions;
Execute the transformation. LEAD finds the next version start. Use [valid_from,valid_to) so a change date belongs to exactly one version; NULL end means current. This lab has unique starts per product. Latest-only output discards history; an as-of join needs all versions.
step-2.sqlSELECT version_id, product_id, valid_from, LEAD(valid_from) OVER(PARTITION BY product_id ORDER BY valid_from,version_id) AS valid_to FROM product_versions;
Test another question. Do not subtract a day from timestamp boundaries; half-open intervals avoid gaps and double matches.
step-3.sqlWITH versions AS( SELECT *, LEAD(valid_from) OVER(PARTITION BY product_id ORDER BY valid_from,version_id) AS valid_to FROM product_versions ) SELECT product_id,cost FROM versions WHERE valid_from<='2025-02-01' AND (valid_to>'2025-02-01' OR valid_to IS NULL)