What it checks
Whether a source table and its target hold the same number of rows, one segment at a time. A whole-table row count tells you that something went missing. Splitting the count by a segment column (a source customer, a region, a line of business) tells you where. If one customer's feed failed to load, only that customer's child test fails, and the other customers keep a clean history.
This is the template to start from when one catalogued table needs several child tests. Every row of the file names the same kind of object, a source table, but the file repeats each table once per segment value. test.key keeps those rows apart: the table appears three times, with three different keys, and produces three child tests.
Part of Template Test Examples: Import File. The same template, with a script that reads the segment values from the data instead of a file, is Metadata Script Example: Reconciliation by Segment.
The template
| Setting | Value |
|---|---|
| Name | Import File Example - Reconciliation by Segment |
| Level | Table |
| Generation source | Import File |
| Severity | High |
| Quality dimension | Completeness |
| Child test name | S2T by {{var.segment_column}}: {{table.name}} -> {{var.target_table}} [{{var.segment_value}}] |
| Child folder | Relative, {{var.template_test_name}} |
| Test data set | Script on the template's data source, single value, numeric (below) |
| Control data set | Script on the template's data source, single value, numeric (below) |
| Value success criteria | Numeric tolerance: {{var.tolerance}} |
| Overall success | Value, tolerance 0 |
| Missing result actions | Fail on both sides |
The test data set counts the source rows in one segment:
SELECT COUNT(*) AS ROW_COUNT
FROM {{schema.name}}.{{table.name}}
WHERE {{var.segment_column}} = '{{var.segment_value}}'
The control data set counts the target rows in the same segment:
SELECT COUNT(*) AS ROW_COUNT
FROM {{var.target_schema}}.{{var.target_table}}
WHERE {{var.segment_column}} = '{{var.segment_value}}'
Variables declared on the template:
| Reference key | Type | Purpose |
|---|---|---|
target_schema |
Schema | Schema of the target table |
target_table |
Table | Target table |
segment_column |
Column | Column that defines the segment, present in both tables |
segment_value |
Other | The one segment value this child test counts |
tolerance |
Numeric | Allowed difference between the two counts. Default 0 |
The source table is the catalogued object, so it carries coverage through the metadata link {{schema.name}}.{{table.name}}. The target is linked through {{var.target_schema}}.{{var.target_table}} on the control data set, without counting as coverage.
The import file
import-file-example-reconciliation-by-segment.xlsx, one sheet, header row plus 15 data rows: five table pairs, each repeated for three source customers.
| Header | Meaning |
|---|---|
schema.name, table.name |
The catalogued source table |
test.key |
TARGET: SOURCE_CUSTOMER = value. Unique per row, so one source table can appear once per segment value |
var.target_schema, var.target_table |
The target table |
var.segment_column |
SOURCE_CUSTOMER on every row |
var.segment_value |
CUSTOMER_1001, CUSTOMER_1002, or CUSTOMER_2001 |
var.tolerance |
0 on every row |
The table pairs:
| Source | Target |
|---|---|
RAW.ACCOUNT |
STAR_SCHEMA.DIM_ACCOUNT |
RAW.POLICY |
STAR_SCHEMA.DIM_POLICY |
RAW.CLAIM |
STAR_SCHEMA.DIM_CLAIM |
RAW.PAYMENT |
STAR_SCHEMA.FACT_PAYMENT |
RAW.TRANSACTION |
STAR_SCHEMA.FACT_TRANSACTION |
The three rows for RAW.CLAIM:
schema.name |
table.name |
test.key |
var.target_table |
var.segment_value |
|---|---|---|---|---|
| RAW | CLAIM | DIM_CLAIM: SOURCE_CUSTOMER = CUSTOMER_1001 | DIM_CLAIM | CUSTOMER_1001 |
| RAW | CLAIM | DIM_CLAIM: SOURCE_CUSTOMER = CUSTOMER_1002 | DIM_CLAIM | CUSTOMER_1002 |
| RAW | CLAIM | DIM_CLAIM: SOURCE_CUSTOMER = CUSTOMER_2001 | DIM_CLAIM | CUSTOMER_2001 |
Leave out test.key and these three rows would all key to raw.claim. Upload would then fail with Duplicate test key: raw.claim.
What materializes
Fifteen child tests, three per source table, in a folder named after the template. The child for claims from CUSTOMER_1002 gets this test script:
SELECT COUNT(*) AS ROW_COUNT
FROM RAW.CLAIM
WHERE SOURCE_CUSTOMER = 'CUSTOMER_1002'
and this control script:
SELECT COUNT(*) AS ROW_COUNT
FROM STAR_SCHEMA.DIM_CLAIM
WHERE SOURCE_CUSTOMER = 'CUSTOMER_1002'
Results on SAMPLE_DW
Verified 2026-10-19: 15 children, 12 pass, 3 fail.
| Pair | CUSTOMER_1001 | CUSTOMER_1002 | CUSTOMER_2001 |
|---|---|---|---|
| ACCOUNT -> DIM_ACCOUNT | Pass | Pass | Pass |
| POLICY -> DIM_POLICY | Pass | Pass | Pass |
| CLAIM -> DIM_CLAIM | Fail: 21,036 vs 20,644 | Fail: 22,576 vs 22,154 | Fail: 10,727 vs 10,515 |
| PAYMENT -> FACT_PAYMENT | Pass | Pass | Pass |
| TRANSACTION -> FACT_TRANSACTION | Pass | Pass | Pass |
The Source to Target Reconciliation example already shows that DIM_CLAIM is short of RAW.CLAIM overall. Split by customer, the shortfall turns out to hit every customer, at roughly the same rate (1.9% to 2.0%). That points at the claim load itself rather than at one customer's feed, which is the kind of conclusion a single whole-table count cannot give you.
Adapting it
Use your own segment column. Change var.segment_column on every row. The column must exist under the same name in both tables. If it is named differently on each side, add a target_segment_column variable and use it in the control SQL.
Segment by more than one column. Put a whole predicate in a variable instead of a column and a value: declare segment_filter and use WHERE {{var.segment_filter}} on both sides, with rows such as REGION = 'EAST' AND CHANNEL = 'WEB'.
Numeric segment values. The SQL quotes the value. For a numeric segment column, drop the quotes in both scripts, or cast the column to text in the WHERE clause.
Let the data decide the segments. The file has to list every customer by hand, so a new customer has no child tests until someone adds rows. The metadata script version reads the customer list from the data at each materialization instead.
Pitfall: a segment that exists on one side only. If a value appears in the target but never in the source, no file row names it and no child test covers it. Count the distinct segment values on both sides, or add a row per value you expect.