Transformação
Tutorial dbt: SQL versionado, testado e documentado
Com dbt você para de manter scripts SQL soltos e passa a manter um projeto: dependências explícitas, testes automáticos, ambientes separados e documentação gerada. Abaixo, o projeto mínimo que já tem qualidade de produção.
Estrutura de projeto que os times usam
meu_projeto/
├── dbt_project.yml
├── models/
│ ├── staging/ # 1 model por tabela de origem, só limpeza
│ │ ├── stg_pedidos.sql
│ │ ├── stg_clientes.sql
│ │ └── _staging.yml # sources + testes
│ ├── intermediate/ # joins e regras reutilizáveis
│ │ └── int_pedidos_enriquecidos.sql
│ └── marts/ # o que o negócio consome
│ ├── fct_pedidos.sql
│ └── dim_clientes.sql
├── macros/
├── snapshots/
└── tests/Regra de ouro: staging não faz join, marts não fazem limpeza. Isso sozinho evita metade da bagunça em projetos dbt.
Seu primeiro model com ref()
-- models/staging/stg_pedidos.sql
{{ config(materialized='view') }}
select
id as pedido_id,
cliente_id,
lower(trim(status)) as status,
valor_centavos / 100.0 as valor,
cast(criado_em as date) as data_pedido
from {{ source('loja', 'pedidos') }}
where criado_em is not null-- models/marts/fct_pedidos.sql
{{ config(materialized='table') }}
with pedidos as (
select * from {{ ref('stg_pedidos') }}
),
clientes as (
select * from {{ ref('stg_clientes') }}
)
select
p.pedido_id,
p.data_pedido,
p.valor,
c.uf,
c.segmento
from pedidos p
left join clientes c on c.cliente_id = p.cliente_id
where p.status = 'pago'Você nunca escreve o nome físico da tabela. O ref() resolve o schema certo em dev e em prod e monta o grafo de execução sozinho.
Testes: a parte que gera confiança
# models/staging/_staging.yml
version: 2
sources:
- name: loja
schema: raw
tables:
- name: pedidos
- name: clientes
models:
- name: stg_pedidos
columns:
- name: pedido_id
tests: [unique, not_null]
- name: cliente_id
tests:
- not_null
- relationships:
to: ref('stg_clientes')
field: cliente_id
- name: status
tests:
- accepted_values:
values: ['pago', 'pendente', 'cancelado']dbt build # roda models + testes na ordem do grafo
dbt run --select marts+ # só marts e o que depende deles
dbt test --select stg_pedidos
dbt docs generate && dbt docs serveModel incremental para tabelas grandes
{{ config(
materialized='incremental',
unique_key='pedido_id',
incremental_strategy='merge'
) }}
select *
from {{ ref('stg_pedidos') }}
{% if is_incremental() %}
where data_pedido >= (select coalesce(max(data_pedido), '1900-01-01') from {{ this }})
{% endif %}Na primeira execução o dbt cria a tabela inteira; nas seguintes, processa só o novo e faz MERGE pela unique_key. É o que derruba custo de warehouse de verdade.
Erros comuns em projetos dbt no Brasil
- Usar nome de tabela cru em vez de
ref()— quebra o grafo e o ambiente de dev. - Model de 400 linhas fazendo tudo. Quebre em staging → intermediate → mart.
- Zero testes: sem
uniqueenot_nullnas chaves, duplicata chega no dashboard. - Tudo como
table: custo alto sem necessidade. Comece com view. - Regra de negócio escondida no BI em vez de estar no mart, versionada no Git.
Perguntas frequentes
- O que é dbt?
- dbt (data build tool) é a camada de transformação do stack moderno: você escreve SELECTs em SQL e o dbt cria as tabelas e views no seu warehouse, na ordem correta, com testes, documentação e versionamento em Git.
- dbt substitui o Airflow?
- Não. O dbt transforma dados dentro do warehouse; o Airflow orquestra quando o dbt roda e o que roda antes e depois. Times maduros usam os dois juntos.
- dbt Core ou dbt Cloud?
- dbt Core é open source e roda via CLI, geralmente dentro do Airflow ou de um container. dbt Cloud adiciona IDE, agendador e permissões gerenciadas. Para aprender e para a maioria dos times pequenos, Core basta.
- O que faz a função ref() no dbt?
- ref('outro_model') referencia outro model e, com isso, o dbt descobre o grafo de dependências automaticamente e resolve o nome real da tabela no ambiente correto (dev, staging, prod).
- Quais materializações existem?
- view (padrão), table, incremental e ephemeral. Use view no staging, table quando a leitura é frequente, incremental para tabelas grandes de fatos e ephemeral para CTEs reutilizáveis que não precisam existir no banco.
- dbt funciona com BigQuery, Snowflake e Databricks?
- Sim, além de Redshift, Postgres, DuckDB e Fabric. Cada um tem um adapter próprio; o SQL muda pouco e o restante do projeto é igual.
Pronto para assinar?
7 dias grátis. Depois, menos que um café por mês — cancele quando quiser.
Assinar — 7 dias grátis- Sem cartão no teste grátis
- Cancele quando quiser
- 300+ exercícios
- 14 cursos completos