This capstone combines every technique from the module — NULL handling, standardization, deduplication, and validation — into a single, realistic pipeline: cleaning a multi-table SaaS customer dataset before it feeds a monthly active accounts report.
Rather than isolated scenarios, this chapter presents one continuous dataset with multiple, layered data quality problems, and walks through building a clean, trustworthy staging layer from raw, messy source tables — the way this work is actually structured in a production analytics engineering role.
Real data cleaning is rarely one function applied once. It’s a sequence: validate structure, standardize text, resolve duplicates, handle NULLs meaningfully, and only then compute business metrics — each step depending on the one before it. This chapter exists to practice that full sequence end to end, rather than each technique in isolation.
A SaaS company tracks accounts (companies) and subscriptions (billing records) across two data sources — a self-serve signup flow and a sales-assisted enterprise flow — that were merged into one warehouse without full reconciliation. Company names are inconsistently formatted, some subscriptions reference accounts that don’t exist, some accounts are duplicated across the two sources, and NULL cancelled_at values are the correct signal for “still active” rather than a data quality problem.
This project produces a clean accounts view suitable for a monthly active accounts (MAA) metric — free of duplicate accounts, orphaned subscriptions, and inconsistent naming — while correctly preserving the business meaning of NULL where NULL is the right answer (active subscriptions).
Raw Layer Cleaning Steps Trusted Layer
─────────── ────────────── ─────────────
accounts_raw ──┐
│ 1. Validate FKs (orphan check)
subscriptions_raw─┤ 2. Standardize company_name
│ 3. Deduplicate accounts
│ 4. Resolve NULL semantics
│ 5. Recompute MAA metric
└──────────────────────────────► accounts_clean
monthly_active_accounts
This chapter is a synthesis of prior syntax — see the accompanying SQL file for the complete pipeline. No new functions are introduced; the focus is sequencing and combining LEFT JOIN, ROW_NUMBER(), COALESCE, TRIM/LOWER, and CASE correctly, in the right order, against a connected dataset.
The order of operations matters. Standardizing company names before deduplicating is required — deduplication logic that groups on raw, unstandardized names will miss duplicates that only differ by casing or whitespace. Validating orphaned foreign keys before computing the final metric prevents a subscription with no valid account from silently contributing to (or breaking) an aggregate. NULL handling for cancelled_at must be resolved last and carefully, since collapsing “still active” into a fallback value like 'N/A' would destroy the exact signal the business relies on to compute active accounts.
For large SaaS datasets, deduplication and standardization steps should run as a scheduled batch job against the staging layer, not inline inside a live reporting query — recomputing ROW_NUMBER() over millions of rows on every dashboard refresh is unnecessary and slow when the result changes only as often as new data loads.
cancelled_at as a data quality gap and “fixing” it with a fallback value, destroying the correct “still active” signalcancelled_at from its first subscription and a NULL cancelled_at from its second — both records are correct and neither should be deduplicated awayThis capstone project demonstrates that production data cleaning is a sequence, not a single query: validate, standardize, deduplicate, then resolve NULL semantics — each step depending on correct execution of the one before it. Getting the order right, and understanding what NULL actually means for each specific column, is what separates a fragile one-off fix from a durable, trustworthy pipeline.
cancelled_at should not be run through COALESCE() with a fallback value in this pipeline.