Not Null Check¶
Check name: not-null-check · Type: row-level · Config: NotNullCheckConfig
Flags any record where one or more of the configured columns contains a value —
that is, it asserts the columns are expected to stay null. Use it for fields
that should remain unset under normal business conditions, such as a
deleted_at or error_reason that must be empty for active records.
Parameters¶
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
check_id |
str |
yes | — | Unique identifier for this check within the CheckSet. |
columns |
list[str] |
yes | — | Columns that must remain null. YAML key: columns. |
severity |
Severity |
no | CRITICAL |
CRITICAL fails the row; WARNING only records it. |
Usage¶
Behavior¶
- OR semantics across columns. A record fails if any of the listed columns is non-null. It is the inverse of the Null Check.
- Failure is row-level. Each failing row is annotated in
_dq_errors; passing rows are unaffected. With the default severity, a failure sets_dq_passed = False. - Missing columns raise. If a configured column does not exist in the
DataFrame, the check raises
MissingColumnErrorat validation time rather than silently passing.
Example¶
Given a DataFrame where deleted_at should be empty for every row, both styles
produce the same result.
from pyspark.sql import SparkSession
from sparkdq.checks import NotNullCheckConfig
from sparkdq.engine import BatchDQEngine
from sparkdq.management import CheckSet
spark = SparkSession.builder.getOrCreate()
df = spark.createDataFrame([
{"id": 1, "deleted_at": None},
{"id": 2, "deleted_at": "2026-01-05"},
{"id": 3, "deleted_at": None},
])
check_set = CheckSet().add_check(
NotNullCheckConfig(check_id="deleted-at-empty", columns=["deleted_at"])
)
result = BatchDQEngine(check_set).run_batch(df)
result.fail_df().show(truncate=False)
import yaml
from pyspark.sql import SparkSession
from sparkdq.engine import BatchDQEngine
from sparkdq.management import CheckSet
spark = SparkSession.builder.getOrCreate()
df = spark.createDataFrame([
{"id": 1, "deleted_at": None},
{"id": 2, "deleted_at": "2026-01-05"},
{"id": 3, "deleted_at": None},
])
with open("checks.yml") as f:
config = yaml.safe_load(f)
check_set = CheckSet()
check_set.add_checks_from_dicts(config)
result = BatchDQEngine(check_set).run_batch(df)
result.fail_df().show(truncate=False)
The failing row is returned with its error metadata:
+----------+---+--------------------------------------------+----------+--------------------------+
|deleted_at|id |_dq_errors |_dq_passed|_dq_validation_ts |
+----------+---+--------------------------------------------+----------+--------------------------+
|2026-01-05|2 |[{NotNullCheck, deleted-at-empty, critical}]|false |2026-01-01 00:00:00.000000|
+----------+---+--------------------------------------------+----------+--------------------------+
Typical use cases¶
- Assert that lifecycle columns like
deleted_atorarchived_atare empty for records that should still be active. - Enforce that an
error_reasonorrejection_codeis null on successfully processed rows. - Catch upstream logic that unexpectedly populates a field that should stay unset.
Related checks¶
- Null Check — the inverse assertion for columns that must be populated.
- Exactly One Not Null Check — require exactly one of several columns to be populated.