How to Validate Fact Table Grain Row Counts in Python

Validate fact table grain by checking dimension key references, unique grain combinations, duplicate rows, and dimension cardinality from a CSV file.

Medium Python 3.9+ Aug 9, 2026 Data pipelines & processing 13 views 0 copies

Python code

58 lines
Python 3.9+
import csv
import hashlib
from pathlib import Path


def validate_fact_grain(fact_file: Path, expected_dim_keys: dict[str, set[str]]) -> dict:
    """
    Validate fact table grain by checking each row's dimension keys exist
    in expected dimension tables and row count consistency.
    """
    dim_references = {}
    with open(fact_file, newline="") as f:
        reader = csv.DictReader(f)
        rows = list(reader)
        for row in rows:
            for dim_name, key_col in expected_dim_keys.items():
                key_value = row.get(key_col)
                if key_value is None:
                    raise ValueError(f"Missing column {key_col}")
                dim_references.setdefault(dim_name, set()).add(key_value)

        # Check grain uniqueness based on all dimension key columns combined
        grain_key_cols = sorted(expected_dim_keys.values())
        seen_grains = set()
        duplicate_count = 0
        for row in rows:
            grain = tuple(row[col] for col in grain_key_cols)
            if grain in seen_grains:
                duplicate_count += 1
            else:
                seen_grains.add(grain)

    return {
        "row_count": len(rows),
        "unique_grain_count": len(seen_grains),
        "duplicate_grain_rows": duplicate_count,
        "dimension_cardinality": {dim: len(keys) for dim, keys in dim_references.items()},
    }


if __name__ == "__main__":
    fact_data = [
        {"order_id": "O1", "product_id": "P1", "qty": "2"},
        {"order_id": "O1", "product_id": "P2", "qty": "1"},
        {"order_id": "O2", "product_id": "P1", "qty": "5"},
        {"order_id": "O1", "product_id": "P1", "qty": "2"},  # duplicate grain
    ]
    fact_path = Path("/tmp/fact_sales.csv")
    with open(fact_path, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["order_id", "product_id", "qty"])
        writer.writeheader()
        writer.writerows(fact_data)

    result = validate_fact_grain(
        fact_path,
        expected_dim_keys={"dim_order": "order_id", "dim_product": "product_id"},
    )
    print(result)

Output

stdout
{'row_count': 4, 'unique_grain_count': 3, 'duplicate_grain_rows': 1, 'dimension_cardinality': {'dim_order': 2, 'dim_product': 2}}

How it works

The function reads a CSV fact table and builds a set of referenced keys for each dimension using setdefault, which ensures unique key tracking. It then constructs a composite grain key from the sorted dimension key columns and detects duplicates by comparing against a seen-grains set. The result returns row counts, unique grain count, duplicate rows, and per-dimension cardinality, giving you a complete picture of grain consistency. This approach relies on the standard library csv and hashlib modules, so no external dependencies are required.

Common mistakes

  • Assuming every row has all dimension key columns, without checking for missing keys first
  • Using a single dimension key instead of all combined keys to define the grain
  • Forgetting to sort the grain key columns, leading to inconsistent grain tuples
  • Counting dimension cardinality as rows referenced rather than unique keys

Variations

  1. Use pandas `groupby().size()` to detect duplicate grains on large fact tables
  2. Implement the same validation with SQL `GROUP BY` on a database fact table

Real-world use cases

  • Verifying that a nightly ETL load hasn't introduced duplicate grain rows in a sales fact table.
  • Auditing dimension key referential integrity before refreshing a customer analytics warehouse.
  • Quality-checking a tracking events fact table to ensure each event maps to exactly one grain.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Data pipelines & processing

Related tutorials and quizzes for this topic.