lesson 81 Warehouse & reporting projects · advanced
Quarantine bad rows & reconcile the batch
Separate invalid records and reconcile the whole batch.
the idea
Filtering invalid rows is not enough: preserve a reject table with source identity, raw value, and reason. Accepted + rejected must equal source count with no overlap. This lab classifies only dates: missing, format, or calendar errors. Nothing edits the raw input.
tables in this lesson
The challenges use this data. Each column shows its type underneath; → marks a link to another table.
raw_dates2 columns · 8 rows
| row_idinteger · key | raw_datetext |
|---|---|
| 1 | 20250115 |
| 2 | 20250230 |
| 3 | 0 |
| 4 | 20240229 |
| 5 | 20251301 |
showing 5 of 8 rows
example
The idea in one query. Press Run to see what it returns; running examples never affects your progress.
CREATE TEMP TABLE checked_dates AS
WITH shaped AS(
SELECT
row_id,
raw_date,
SUBSTR(raw_date,1,4)||'-'||SUBSTR(raw_date,5,2)||'-'||SUBSTR(raw_date,7,2) AS candidate
FROM raw_dates
)
SELECT
row_id,
raw_date,
CASE
WHEN raw_date GLOB '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
AND date(candidate,'+0 days')=candidate
THEN candidate
ELSE NULL
END AS clean_date
FROM shaped;
CREATE TEMP TABLE date_rejects AS
SELECT
row_id,
raw_date,
CASE
WHEN raw_date IS NULL THEN 'missing'
WHEN raw_date NOT GLOB '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
THEN 'format'
ELSE 'calendar'
END AS reason
FROM checked_dates
WHERE clean_date IS NULL;
SELECT row_id,raw_date,reason
FROM date_rejects;Watch for: One row can violate several rules in a general pipeline. A primary reason must be deterministic; multiple reason records require distinct row counting.
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 raw_dates;
Execute the transformation. Filtering invalid rows is not enough: preserve a reject table with source identity, raw value, and reason. Accepted + rejected must equal source count with no overlap. This lab classifies only dates: missing, format, or calendar errors. Nothing edits the raw input.
step-2.sqlCREATE TEMP TABLE checked_dates AS WITH shaped AS( SELECT row_id, raw_date, SUBSTR(raw_date,1,4)||'-'||SUBSTR(raw_date,5,2)||'-'||SUBSTR(raw_date,7,2) AS candidate FROM raw_dates ) SELECT row_id, raw_date, CASE WHEN raw_date GLOB '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' AND date(candidate,'+0 days')=candidate THEN candidate ELSE NULL END AS clean_date FROM shaped; CREATE TEMP TABLE date_rejects AS SELECT row_id, raw_date, CASE WHEN raw_date IS NULL THEN 'missing' WHEN raw_date NOT GLOB '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' THEN 'format' ELSE 'calendar' END AS reason FROM checked_dates WHERE clean_date IS NULL; SELECT row_id,raw_date,reason FROM date_rejects;Test another question. One row can violate several rules in a general pipeline. A primary reason must be deterministic; multiple reason records require distinct row counting.
step-3.sqlCREATE TEMP TABLE checked_dates AS WITH shaped AS( SELECT row_id, raw_date, SUBSTR(raw_date,1,4)||'-'||SUBSTR(raw_date,5,2)||'-'||SUBSTR(raw_date,7,2) AS candidate FROM raw_dates ) SELECT row_id, raw_date, CASE WHEN raw_date GLOB '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' AND date(candidate,'+0 days')=candidate THEN candidate ELSE NULL END AS clean_date FROM shaped; SELECT ( SELECT COUNT(*) FROM raw_dates ) AS source_rows, SUM(clean_date IS NOT NULL) AS accepted_rows, SUM(clean_date IS NULL) AS rejected_rows, COUNT(*)=( SELECT COUNT(*) FROM raw_dates ) AS reconciled FROM checked_dates