Handbook contents

Learn 11~13 min

Building and checking a change

Editing a model changes a file. Building it changes a warehouse object. Checking the result establishes what evidence you have for the proposed analytical change.

Read the model before running it

Suppose you are changing a person-level appointment summary. Begin with its description: who appears, which appointments count and what period it covers. Then read the SQL in stages. The following fictional model has one intermediate query and one final query; the names beginning with example_ are illustrative, not models to run in the project.

example_person_appointments.sql
with attended as (
    select person_id, appointment_id
    from {{ ref('example_appointments') }}
    where status = 'attended'
)

select
    person_id,
    count(*) as attended_appointments
from attended
group by person_id

The with block gives the filtered query a local name, attended. This is a common table expression, or CTE. It helps us read the query in steps; it does not create another warehouse table. The final SELECT groups the qualifying appointment rows by person.

The output contains people with at least one attended appointment. It has no date filter, so its period is whatever history the input provides. Those facts are more important than whether the SQL looks tidy. If the description promises every person or the last twelve months, the implementation does not match it.

Choose the command for the question

dbt commands do different work. A successful command establishes only what that command checked. Here, my_model stands for the real model you are working on.

CommandWhat happensWhat remains to check
dbt compile -s my_modelRenders the model's templates into SQL. Fusion can also analyse SQL using available catalogue metadata.The model's query has not been materialised and its data tests have not run.
dbt run -s my_modelExecutes the model using its materialisation.Data tests do not run as part of this command.
dbt test -s my_modelRuns the tests selected for the model.Data tests inspect the existing relation; they do not first rebuild it from your edited SQL.
dbt build -s my_modelBuilds selected resources and runs selected tests in dependency order.Inspect the output and judge whether the change meets the analytical requirement.

For a normal model change, a focused dbt build gives evidence about both execution and the selected assertions. Read its summary to confirm which models and tests actually ran. Tests involving several parents have selection rules too; do not assume every related test was included.

Use the project's development target. In this project, development writes to DEV__ databases and reads the shared data lake where needed. Those databases are not automatically private to your Git branch. Check the resolved relation and coordinate if someone else is developing the same model.

The official build and run references describe command behaviour and test selection in more detail.

Select the dependencies you need to exercise

A reference declares a dependency; selection determines which resources this command runs. Selecting one model does not automatically rebuild all its parents. If an upstream model is new or has changed too, it may need to be selected.

SelectionModel scopeWhy choose it?
my_modelThe named modelCheck its change using available inputs.
+my_modelThe model and its ancestorsRebuild required upstream resources before checking the result.
my_model+The model and its descendantsExercise consumers that may be affected by the change.

Use dbt ls -s my_model+ --output name to inspect a selection before running it. A shared person model can have many descendants. Start with the scope needed to investigate the change, then widen the validation where its impact warrants it. A short command can select a large part of the warehouse.

Know whether you are building a view or a table

A materialisation is how dbt implements the model in the warehouse. A normal view stores a query definition and reads its inputs when queried. A table stores the results produced when it is built. If the source changes afterwards, that table needs another refresh before it reflects the change.

This affects investigation. If a view reads a table last refreshed yesterday, the view does not make that input current. Conversely, querying a view twice can return different rows if its inputs changed. Record the source period and the build time when comparing results.

Project configuration supplies defaults, and a model can override them. Inspect the effective configuration before assuming how it refreshes. Incremental models process a selected portion of data on later runs; changing their SQL may leave older rows untouched. The materialisations chapter explains those choices and when history needs rebuilding.

Reconcile the analytical change

A green build is a starting point for validation. Suppose a change to the appointment summary increases a provider's total from 100 to 112. You expected additional attended appointments from a newly covered service, but the size of the increase alone cannot establish that explanation.

Compare old and new results for the same reporting period and, where possible, the same inputs. Otherwise, a new source delivery can look like an effect of the code change. Compare the number of rows and distinct keys, then identify records added, removed or changed. Break the difference down by the affected service or status rather than checking only the grand total.

Illustrative findingWhat to investigate
12 new appointment identifiers, all from the added serviceWhether those records meet the agreed criteria and belong to the period.
12 more rows, but no new appointment identifiersA join or duplicated input may have repeated existing appointments.
Same total, but 12 records added and 12 removedA changed population that the total conceals.

For joins, also compare matched and unmatched records. An unchanged row count can hide missing attributes, and a larger count can be a legitimate grain change or an unintended fan-out. The intended contract determines which evidence matters.

Inspect a few deliberately chosen cases: one that should be included, one excluded, a boundary date and missing evidence. Use an approved environment for real row-level inspection. Keep patient records and identifying results out of repository files, public PRs and assistant output. Fictional examples can explain the logic; suitable non-identifying aggregates can record validation evidence.

A failure tells you where to investigate

A template or compilation error concerns preparing the query. An execution error means the warehouse could not complete it. A failing data test means the resulting rows violate an assertion. Find the first relevant error and separate it from descendants skipped because their input failed.

Do not weaken a test merely to obtain a green run. Inspect whether the source changed, the implementation is wrong or the test expresses an inappropriate assumption. If the assumption was wrong, update the description and explain the decision alongside the test change.

The local build field guide gives the commands and failure-reading steps. Once the model and its evidence are ready, Git and pull requests explains how the team reviews the proposed change.

What does the evidence establish?

0/2 answered
  1. 1You edit a model, then run only its data tests. What do those tests inspect?

  2. 2Old and new provider totals agree. What should you conclude?