Vereisten en installatie

dbt Core vereist Python 3.8+ en wordt geïnstalleerd via pip. Het belangrijkste is om te installeren niet alleen het basispakket maar ook despecifieke adapter voor uw magazijn. Elk magazijn heeft zijn eigen adapter, omdat SQL-dialecten verschillen.

# Installa dbt Core con l'adapter per PostgreSQL (ottimo per iniziare in locale)
pip install dbt-postgres

# Per BigQuery
pip install dbt-bigquery

# Per Snowflake
pip install dbt-snowflake

# Per DuckDB (ideale per sviluppo locale senza infrastruttura)
pip install dbt-duckdb

# Verifica l'installazione
dbt --version
# Core:
#   - installed: 1.9.0
#   - latest:    1.9.0 - Up to date!

Ga aan de slag met DuckDB voor lokale ontwikkeling

Als u niet onmiddellijk toegang heeft tot BigQuery of Snowflake, DuckDB het is de manier sneller aan de slag: het is een embedded database die direct lokaal draait, vereist geen infrastructuur en dbt-duckdb werkt op elke machine. Perfect om te leren zonder kosten.

Creëer het eerste dbt-project

Het commando dbt init creëert de mappenstructuur van een dbt-project en begeleidt u in de initiële configuratie:

dbt init jaffle_shop

# dbt chiederà:
# 1. Quale database vuoi usare? (postgres/bigquery/snowflake/...)
# 2. [Per postgres] host, port, user, password, database, schema

# La struttura creata:
jaffle_shop/
├── dbt_project.yml          # configurazione principale
├── README.md
├── analyses/               # query ad hoc (non materializzate)
├── macros/                 # funzioni Jinja riutilizzabili
├── models/
│   └── example/            # modelli di esempio (da eliminare)
├── seeds/                  # CSV statici
├── snapshots/              # snapshot per SCD
└── tests/                  # test SQL singolari

Het dbt_project.yml-bestand

Het hart van de projectconfiguratie is dbt_project.yml. Definieer hier projectnaam, dbt-versie, mappaden en globale configuratie van de modellen:

# dbt_project.yml
name: 'jaffle_shop'
version: '1.0.0'

# Versione minima di dbt richiesta
require-dbt-version: ">=1.8.0"

# Percorso del profile da usare (in profiles.yml)
profile: 'jaffle_shop'

# Directory dei modelli
model-paths: ["models"]
analysis-paths: ["analyses"]
test-paths: ["tests"]
seed-paths: ["seeds"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]

# Dove salvare i log e i target compilati
target-path: "target"
log-path: "logs"
clean-targets: ["target", "dbt_packages"]

# Configurazione dei modelli per directory
models:
  jaffle_shop:
    # Tutti i modelli del progetto sono view per default
    +materialized: view

    staging:
      # I modelli in staging/ sono sempre view
      +materialized: view
      +schema: staging          # savedano in schema 'staging'

    marts:
      +materialized: table      # I marts sono table per performance
      +schema: marts

Het profielen.yml-bestand

De verbindingsreferenties gaan binnen ~/.dbt/profiles.yml (in de thuismap, nooit in de opslagplaats). Elk profiel kan meerdere doelen hebben (ontwikkelaar, staging, productie):

# ~/.dbt/profiles.yml
jaffle_shop:
  target: dev                    # target di default

  outputs:
    dev:
      type: postgres
      host: localhost
      port: 5432
      user: "{{ env_var('DB_USER') }}"      # usa variabili d'ambiente
      password: "{{ env_var('DB_PASSWORD') }}"
      dbname: jaffle_shop_dev
      schema: dbt_dev_federico   # schema personale per sviluppo
      threads: 4

    prod:
      type: postgres
      host: "{{ env_var('PROD_DB_HOST') }}"
      port: 5432
      user: "{{ env_var('PROD_DB_USER') }}"
      password: "{{ env_var('PROD_DB_PASSWORD') }}"
      dbname: jaffle_shop_prod
      schema: dbt_prod
      threads: 8

De afspraak is dat elke ontwikkelaar een persoonlijk patroon heeft (bijv. dbt_dev_federico) om conflicten tijdens parallelle ontwikkeling te vermijden.

dbt-modellen: de fundamentele eenheid

Een dbt-model is een bestand .sql in de map models/. De inhoud het is een simpele SELECTIE: dbt zorgt voor het creëren van de corresponderende weergave of tabel in het magazijn.

Laten we beginnen met een realistisch voorbeeld. Stel dat we een tafel hebben raw.orders binnen magazijn met ruwe data uit de applicatie:

-- models/staging/stg_orders.sql
-- Staging model: rinomina, casta, pulisce — nessuna logica di business

WITH source AS (
    SELECT * FROM {{ source('raw', 'orders') }}   -- 'source' punta alla sorgente raw
),

renamed AS (
    SELECT
        id                                         AS order_id,
        user_id                                    AS customer_id,
        order_date                                 AS created_at,
        status,
        CAST(amount AS DECIMAL(10,2))              AS total_amount,
        LOWER(payment_method)                      AS payment_method,
        _loaded_at                                 AS loaded_at    -- metadata pipeline
    FROM source
    WHERE id IS NOT NULL                           -- filtra record corrotti
)

SELECT * FROM renamed

De ref()-macro

De macro ref() het is het belangrijkste kenmerk van dgt. Wanneer je schrijft {{ ref('stg_orders') }}, dbt:

  1. Bepaalt de juiste naam van de tabel/weergave in het magazijn voor de huidige omgeving
  2. Leg de afhankelijkheid vast in de gerichte acyclische grafiek (DAG)
  3. Zorgt ervoor dat het afhankelijke model als eerste wordt uitgevoerd
-- models/marts/finance/orders_monthly.sql
-- Usa ref() per dipendere da stg_orders

WITH orders AS (
    SELECT * FROM {{ ref('stg_orders') }}          -- dbt risolve automaticamente lo schema
),

monthly_aggregated AS (
    SELECT
        DATE_TRUNC('month', created_at)            AS month,
        payment_method,
        COUNT(*)                                   AS order_count,
        SUM(total_amount)                          AS gross_revenue,
        AVG(total_amount)                          AS avg_order_value,
        COUNT(DISTINCT customer_id)                AS unique_customers
    FROM orders
    WHERE status = 'completed'
    GROUP BY 1, 2
)

SELECT * FROM monthly_aggregated

De source()-macro

Om toegang te krijgen tot onbewerkte bronnen (tabellen die niet door dbt zijn gemaakt), gebruikt u source() in plaats van ref(). De bronnen moeten in een bestand worden aangegeven sources.yml:

# models/staging/sources.yml
version: 2

sources:
  - name: raw                    # nome del source group
    database: raw_db             # database nel warehouse
    schema: public               # schema nel warehouse
    tables:
      - name: orders
        description: "Ordini grezzi dall'applicazione"
        loaded_at_field: _loaded_at    # campo per freshness check
        freshness:
          warn_after: {count: 12, period: hour}
          error_after: {count: 24, period: hour}
      - name: customers
        description: "Clienti grezzi dall'applicazione"

Met deze opstelling kun je rennen dbt source freshness om dat te verifiëren de bronnen worden bijgewerkt voordat de transformaties worden gestart.

Voer dbt uit: de basisopdrachten

# Esegui tutti i modelli (materialization nel warehouse)
dbt run

# Esegui solo i modelli staging
dbt run --select staging

# Esegui un singolo modello e tutte le sue dipendenze (+)
dbt run --select +orders_monthly

# Esegui tutti i test definiti nello schema YAML
dbt test

# Testa solo un modello specifico
dbt test --select stg_orders

# Compila i modelli senza eseguirli (utile per debug)
dbt compile

# Verifica freshness delle sorgenti
dbt source freshness

# Genera e serve la documentazione
dbt docs generate
dbt docs serve                  # apre http://localhost:8080

Aanbevolen sjabloonstructuur

De drieledige structuur aanbevolen door de dbt-gemeenschap:

models/
├── staging/                    # Layer 1: vicino alla sorgente
│   ├── sources.yml            # dichiarazione sorgenti
│   ├── schema.yml             # test + documentazione
│   ├── stg_orders.sql
│   ├── stg_customers.sql
│   └── stg_products.sql
├── intermediate/               # Layer 2: join complessi (opzionale)
│   ├── int_orders_enriched.sql # join ordini + clienti
└── marts/                      # Layer 3: pronti per consumo
    ├── finance/
    │   ├── schema.yml
    │   ├── orders_monthly.sql
    │   └── revenue_by_country.sql
    └── marketing/
        └── customer_cohorts.sql

Antipatroon: bedrijfslogica in staging

Staging-sjablonen hoeven alleen "domme" bewerkingen uit te voeren: kolommen hernoemen, cast-typen, ontdubbelen. De bedrijfslogica (berekeningen, aggregaties, joins) gaat naar de tussenmodellen of marten. Als uw stagingmodel een GROUP BY of meer dan een paar berekende kolommen heeft, je doet waarschijnlijk te veel in die laag.

De installatie controleren met dbt debug

Voordat je gaat rennen dbt run, controleer of de magazijnverbinding werkt:

dbt debug

# Output atteso:
# Configuration:
#   profiles.yml file [OK found and valid]
#   dbt_project.yml file [OK found and valid]
# Required dependencies:
#  - git [OK found]
# Connection:
#   host: localhost
#   port: 5432
#   user: federico
#   database: jaffle_shop_dev
#   schema: dbt_dev_federico
#   [OK connection ok]

Conclusies en volgende stappen

We hebben een werkend dbt-project geconfigureerd met de structuur op drie niveaus (staging → tussenproduct → mars), de verbindingsprofielen voor verschillende omgevingen, de aangegeven bronnen met versheidscontrole en de eerste modellen met ref() e source().

De volgende stap is om onze SQL dynamisch te maken met Jinja: variabelen, lussen, voorwaarden en herbruikbare macro's die duplicatie van code in het magazijn elimineren.