Learn  /  Guides

Data quality tests every pipeline needs

Six checks that catch most data problems before your stakeholders do.

Guide8 min readUpdated 30 September 2026
Data qualitySQLdbtPython
All guides and cheat sheets

The worst way to discover a data problem is when a manager asks why the dashboard shows revenue doubling overnight. Data quality tests are small, automatic checks that run with every pipeline and stop bad data before it reaches a report. You do not need an expensive platform to start. Six checks cover the vast majority of real-world issues.

The six checks at a glance

1. Uniqueness
One row per thing. Duplicates inflate totals.
2. Completeness
No missing critical values.
3. Referential integrity
Every key has a match in its lookup table.
4. Accepted values
Statuses, ranges and dates make sense.
5. Freshness
The data is up to date.
6. Volume
Row counts are roughly what you expect.

1. Uniqueness: one row per thing

If a table is meant to have one row per order, prove it. Duplicate keys cause fan-out in joins and inflated totals.

SQL
SELECT order_id, COUNT(*) AS n
FROM fct_orders
GROUP BY order_id
HAVING COUNT(*) > 1;   -- any row returned is a failure

2. Completeness: no missing critical values

SQL
SELECT COUNT(*) AS missing
FROM fct_orders
WHERE customer_id IS NULL OR order_date IS NULL OR amount IS NULL;

3. Referential integrity: every key has a match

Orders pointing at customers that do not exist will vanish from inner joins and show as "blank" in Power BI.

SQL
SELECT o.order_id, o.customer_id
FROM fct_orders o
LEFT JOIN dim_customers c ON c.customer_id = o.customer_id
WHERE c.customer_id IS NULL;

4. Accepted values and ranges

SQL
SELECT *
FROM fct_orders
WHERE order_status NOT IN ('completed', 'refunded', 'cancelled')
   OR amount < 0
   OR order_date > CURRENT_DATE;

5. Freshness: is the data up to date?

SQL
SELECT MAX(_loaded_at) AS last_load,
       DATEDIFF('hour', MAX(_loaded_at), CURRENT_TIMESTAMP()) AS hours_old
FROM raw.orders
HAVING DATEDIFF('hour', MAX(_loaded_at), CURRENT_TIMESTAMP()) > 24;

6. Volume: did we get roughly what we expected?

Compare today's row count with the recent average. A sudden drop usually means a broken extract; a sudden spike often means duplicates.

SQL
WITH daily AS (
    SELECT order_date, COUNT(*) AS n
    FROM fct_orders
    WHERE order_date >= CURRENT_DATE - 29
    GROUP BY order_date
)
SELECT *
FROM daily
WHERE order_date = CURRENT_DATE - 1
  AND n NOT BETWEEN
      0.5 * (SELECT AVG(n) FROM daily WHERE order_date < CURRENT_DATE - 1)
  AND 2.0 * (SELECT AVG(n) FROM daily WHERE order_date < CURRENT_DATE - 1);

The same checks in dbt and Python

If you use dbt, the first four checks are one line each, and freshness is built in. See the dbt guide for a full example. For smaller pipelines built with pandas, a few assertions before saving or sending a report go a long way.

YAML
columns:
  - name: order_id
    data_tests: [unique, not_null]
  - name: customer_id
    data_tests:
      - relationships:
          to: ref('dim_customers')
          field: customer_id

What to do when a test fails

  1. 1

    Decide severity up front

    Some failures should stop the pipeline; others should warn and continue.

  2. 2

    Alert a person

    A failing test nobody sees is not a test.

  3. 3

    Fix the cause, not the symptom

    Filtering out duplicates in the report hides a problem that will return.

  4. 4

    Add a test for every bug you fix

    So the same issue can never slip through twice.

Check your understanding

1/3Revenue doubled overnight and order IDs appear twice. Which test would have caught it?

2/3Orders point at customer IDs that do not exist. Which test fails?

3/3Yesterday's row count is a fifth of the usual. What does that usually mean?

Good tests matter even more when AI reads your data: see the semantic layer for AI agents.

Alessandro Ecclesie AgazziWritten by Alessandro Ecclesie Agazzi, analytics engineer in London. Updated 30 September 2026. About me

Found this useful?

New guides and "what's new" explainers on data and AI land here regularly. Follow along on LinkedIn, or share this one with a colleague.