A model is SQL with Jinja in it: ref(), source(), variables, macros, loops. When a query fails or returns something unexpected, the first step is to look at the plain SQL dbt produced from it. You can then paste it into the warehouse console and debug it there.

Copy and paste

dbt compile -s customer_orders                                  # print the compiled SQL
cat target/compiled/shop/models/marts/customer_orders.sql       # the same, from the file
cat target/run/shop/models/marts/customer_orders.sql            # the statement dbt executed
dbt compile --inline "select * from {{ ref('customer_orders') }}"

The output of dbt compile -s customer_orders:

Compiled node 'customer_orders' is:
select c.customer_id, c.name, count(o.order_id) as orders, sum(o.amount) as revenue
from "shop"."main"."stg_customers" c
left join "shop"."main"."stg_orders" o on o.customer_id = c.customer_id
group by c.customer_id, c.name

The ref() calls have become full table names, with the database and schema of the current target.

compiled and run

dbt writes two versions of every model in the target folder:

Folder Contains
target/compiled/<project>/models/... the select, with the Jinja resolved
target/run/<project>/models/... the full statement: create table ... as (...), the merge of an incremental model, and so on

target/compiled is written by dbt compile, dbt run and dbt build. target/run only by the commands that execute models. Both reflect the last command, so after compiling with other variables or another target, the files change.

Useful variations

Tested with dbt Core 1.12.

References