dbt per Data Analyst nel 2026: Modellazione, Testing e Domande da Colloquio

Padroneggiare dbt (data build tool) per la data analytics — struttura del progetto, modellazione SQL, strategie di testing e domande frequenti nei colloqui con esempi pratici.

dbt data build tool modellazione e testing per data analyst

dbt (data build tool) si è affermato come lo strato di trasformazione standard nel moderno data stack. Le posizioni di data analyst nel 2026 richiedono sempre più competenze pratiche su dbt. Con dbt Core v2.0 in fase alpha e la versione stabile v1.12, il framework copre ormai tutto — dalla modellazione SQL al testing automatizzato fino alla documentazione — il tutto versionato in Git.

Questa guida affronta la struttura dei progetti dbt, i pattern di modellazione, le strategie di testing e le domande poste più frequentemente nei colloqui per posizioni di data analyst e data engineering.

dbt nella pipeline ELT

dbt gestisce la T (Transform) in ELT. I dati grezzi arrivano nel warehouse tramite strumenti di ingestion (Fivetran, Airbyte), quindi dbt li trasforma in modelli puliti, testati e documentati, pronti per l'analisi. A differenza dell'ETL tradizionale, le trasformazioni vengono eseguite direttamente nel warehouse utilizzando SQL.

Struttura del progetto dbt: Staging, Intermediate e Marts

Un progetto dbt ben organizzato segue un'architettura a strati. Ogni strato ha una responsabilità specifica, e questa separazione previene query SQL disordinate che diventano impossibili da mantenere.

La convenzione standard prevede tre strati:

  • Staging — modelli sottili che rinominano, convertono i tipi e puliscono i dati grezzi dalle sorgenti. Un modello staging per ogni tabella sorgente.
  • Intermediate — logica di business che unisce e aggrega i modelli staging. Sono blocchi costruttivi interni.
  • Marts — modelli finali consumati da dashboard, report e analisti. Ogni mart rappresenta un'entità di business o una metrica.
sql
-- models/staging/stripe/stg_stripe__payments.sql
with source as (
    select * from {{ source('stripe', 'payments') }}
),

renamed as (
    select
        id as payment_id,
        amount / 100.0 as amount_usd,  -- Stripe stores cents
        status as payment_status,
        created::timestamp as created_at,
        customer_id
    from source
    where status != 'failed'  -- Filter invalid records early
)

select * from renamed
sql
-- models/marts/finance/fct_monthly_revenue.sql
with payments as (
    select * from {{ ref('stg_stripe__payments') }}
),

monthly as (
    select
        date_trunc('month', created_at) as revenue_month,
        count(*) as total_transactions,
        sum(amount_usd) as gross_revenue,
        sum(case when payment_status = 'refunded' then amount_usd else 0 end) as refunds
    from payments
    group by 1
)

select
    revenue_month,
    total_transactions,
    gross_revenue,
    refunds,
    gross_revenue - refunds as net_revenue  -- Key business metric
from monthly

Il modello staging si occupa della conversione dei tipi e della rinomina delle colonne. Il modello mart contiene la logica di business. Questa separazione significa che una modifica nello schema sorgente richiede l'aggiornamento di un solo modello staging, non di ogni query a valle.

Materializzazioni: Scegliere la strategia giusta

dbt supporta quattro materializzazioni principali che controllano come i modelli vengono persistiti nel warehouse. La scelta sbagliata porta a query lente oppure a costi di calcolo non necessari.

| Materializzazione | Caso d'uso | Comportamento di rebuild | |-------------------|------------|-------------------------| | view | Modelli staging leggeri, bassa frequenza di query | Ricreata come SQL view ad ogni esecuzione | | table | Modelli mart interrogati spesso dalle dashboard | Ricostruzione completa della tabella ad ogni esecuzione | | incremental | Tabelle dei fatti grandi (eventi, log) | Aggiunge/merge solo le nuove righe | | ephemeral | CTE riutilizzabili, mai interrogate direttamente | Compilata inline come subquery |

I modelli incrementali meritano attenzione speciale perché affrontano il collo di bottiglia più comune nelle performance — l'elaborazione di miliardi di righe ad ogni esecuzione.

sql
-- models/marts/product/fct_page_views.sql
{{ config(
    materialized='incremental',
    unique_key='page_view_id',
    incremental_strategy='merge'
) }}

with events as (
    select
        event_id as page_view_id,
        user_id,
        page_url,
        session_id,
        event_timestamp
    from {{ ref('stg_snowplow__events') }}
    where event_type = 'page_view'

    {% if is_incremental() %}
        -- Only process new events since last run
        and event_timestamp > (select max(event_timestamp) from {{ this }})
    {% endif %}
)

select * from events

La macro is_incremental() verifica se il modello esiste già. Alla prima esecuzione, dbt elabora tutti i dati. Nelle esecuzioni successive, vengono elaborate solo le nuove righe — riducendo un job di due ore a pochi minuti.

Testare la qualità dei dati con dbt

Il testing in dbt opera su due livelli: test dello schema definiti in YAML e test personalizzati scritti in SQL. Entrambi vengono eseguiti con dbt test e fanno fallire la pipeline se vengono trovate violazioni.

I test dello schema coprono i controlli di qualità dei dati più comuni senza scrivere SQL:

yaml
# models/staging/stripe/_stripe__models.yml
version: 2

models:
  - name: stg_stripe__payments
    description: "Cleaned payment records from Stripe"
    columns:
      - name: payment_id
        description: "Unique payment identifier"
        tests:
          - unique
          - not_null
      - name: payment_status
        tests:
          - accepted_values:
              values: ['succeeded', 'pending', 'refunded']
      - name: amount_usd
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: ">= 0"  # No negative payments

Per logica di validazione complessa che YAML non riesce a esprimere, i test singolari personalizzati colmano la lacuna:

sql
-- tests/assert_revenue_not_negative.sql
-- This test fails if any month has negative net revenue
select
    revenue_month,
    net_revenue
from {{ ref('fct_monthly_revenue') }}
where net_revenue < 0  -- Should never happen

Qualsiasi riga restituita da un test singolare indica un fallimento. Questo pattern intercetta corruzione dei dati, bug upstream e errori logici prima che raggiungano le dashboard.

Pronto a superare i tuoi colloqui su Data Analytics?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Jinja e Macro: Logica SQL riutilizzabile

dbt utilizza il templating Jinja per rendere il SQL dinamico. Le due funzioni più importanti sono ref() per i riferimenti ai modelli e source() per i riferimenti ai dati grezzi. Oltre a queste, le macro eliminano pattern SQL ripetitivi nell'intero progetto.

sql
-- macros/cents_to_dollars.sql
{% macro cents_to_dollars(column_name) %}
    ({{ column_name }} / 100.0)::numeric(12, 2)
{% endmacro %}
sql
-- Usage in any model
select
    payment_id,
    {{ cents_to_dollars('amount_cents') }} as amount_usd,
    {{ cents_to_dollars('tax_cents') }} as tax_usd
from {{ source('stripe', 'payments') }}

La macro viene compilata in SQL standard al momento della build. Questo approccio garantisce una logica di conversione valutaria consistente in ogni modello che gestisce valori monetari — una singola modifica nella macro si propaga ovunque.

Domande da colloquio su dbt per Data Analyst

Gli intervistatori che valutano la conoscenza di dbt si concentrano sulla comprensione pratica dello strumento piuttosto che su definizioni memorizzate. Le seguenti domande compaiono regolarmente nei colloqui per posizioni di data analytics.

D1: Qual è la differenza tra ref() e source()?

source() punta alle tabelle grezze caricate dagli strumenti di ingestion e definite in un file sources.yml. ref() punta ad altri modelli dbt. L'utilizzo di ref() costruisce il DAG (directed acyclic graph) che dbt usa per determinare l'ordine di esecuzione e tracciare la lineage dei dati. L'hardcoding dei nomi delle tabelle al posto di ref() interrompe il tracciamento della lineage e impedisce a dbt di eseguire i modelli nell'ordine corretto.

D2: Quando si dovrebbe usare un modello incrementale invece di una tabella?

I modelli incrementali sono appropriati quando i dati sorgente sono append-only o hanno una colonna timestamp affidabile, e la tabella è abbastanza grande da rendere le ricostruzioni complete troppo lente o costose. Tabelle di eventi, dati di log e serie temporali sono candidati tipici. Le tabelle dimensionali piccole dovrebbero rimanere come materializzazione table perché la complessità della logica incrementale non è giustificata.

D3: Come gestisce dbt le Slowly Changing Dimensions (SCD Tipo 2)?

Gli snapshot di dbt implementano il tracking SCD Tipo 2. Uno snapshot monitora una tabella sorgente e registra i cambiamenti nel tempo aggiungendo le colonne dbt_valid_from e dbt_valid_to. Esistono due strategie: timestamp (usa una colonna updated_at) e check (confronta direttamente i valori delle colonne). Gli snapshot vengono eseguiti con dbt snapshot, separatamente da dbt run.

D4: Spiegare il pattern staging/intermediate/marts.

I modelli staging puliscono e rinominano i dati grezzi delle sorgenti — un modello per tabella sorgente, nessun join, nessuna aggregazione. I modelli intermediate contengono la logica di business: join, filtri e calcoli che servono come blocchi costruttivi. I modelli mart sono gli output finali consumati da analisti e dashboard. Questa stratificazione assicura che ogni modello abbia una singola responsabilità e che i cambiamenti nello schema sorgente impattino solo i modelli staging.

D5: Come si differenziano i test personalizzati dai test dello schema?

I test dello schema sono dichiarati in YAML e coprono controlli standard: unique, not_null, accepted_values e relationships. I test singolari personalizzati sono query SQL archiviate nella directory tests/ — qualsiasi riga restituita indica un fallimento. I test generici personalizzati sono macro parametrizzate riutilizzabili tra modelli come i test dello schema. I test dello schema si usano per vincoli comuni, i test singolari per regole di business complesse come "il fatturato non deve mai essere negativo."

Best Practice dbt per progetti in produzione

I progetti dbt in produzione che crescono oltre una manciata di modelli richiedono convenzioni consistenti. Queste pratiche prevengono il debito tecnico che si accumula quando più analisti contribuiscono allo stesso progetto.

Le convenzioni di nomenclatura mantengono il progetto navigabile. I modelli staging usano il prefisso stg_, i modelli intermediate usano int_, e le tabelle dei fatti/dimensioni usano fct_ o dim_. Le sottodirectory specifiche per sorgente (models/staging/stripe/, models/staging/salesforce/) raggruppano modelli correlati.

La documentazione vive accanto al codice. Ogni modello e colonna dovrebbe avere una description nel file YAML corrispondente. L'esecuzione di dbt docs generate produce un sito di documentazione navigabile con un DAG visuale — essenziale per l'onboarding di nuovi membri del team e l'audit della lineage dei dati.

I controlli di freshness delle sorgenti intercettano i fallimenti upstream prima che si propaghino:

yaml
# models/staging/stripe/_stripe__sources.yml
version: 2

sources:
  - name: stripe
    database: raw
    schema: stripe
    freshness:
      warn_after: {count: 12, period: hour}
      error_after: {count: 24, period: hour}
    loaded_at_field: _fivetran_synced
    tables:
      - name: payments
      - name: customers

L'esecuzione di dbt source freshness verifica se i dati sorgente sono stati aggiornati entro la finestra temporale prevista. Un gap di 24 ore nei dati di pagamento segnala un fallimento dell'ingestion che richiede investigazione prima di eseguire le trasformazioni.

Per approfondire le competenze SQL applicate nei modelli dbt, le guide sulle window function SQL e CTE e SQL avanzato per i colloqui trattano i pattern di query utilizzati più frequentemente nei modelli staging e mart.

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Conclusione

  • dbt gestisce lo strato di trasformazione nelle pipeline ELT, eseguendo SQL direttamente nel data warehouse senza richiedere un motore di calcolo separato
  • Il pattern staging/intermediate/marts separa la pulizia delle sorgenti dalla logica di business, rendendo le modifiche prevedibili e isolate
  • Le materializzazioni incrementali riducono i tempi di elaborazione per tabelle grandi, gestendo solo le righe nuove o aggiornate
  • I test dello schema (YAML) coprono vincoli standard; i test singolari (SQL) validano regole di business complesse
  • Le macro Jinja eliminano logica SQL ripetuta e garantiscono consistenza tra i modelli
  • I controlli di freshness delle sorgenti intercettano fallimenti di ingestion upstream prima che corrompano i modelli a valle
  • La preparazione ai colloqui dovrebbe concentrarsi su scenari pratici — lineage del DAG, trade-off delle materializzazioni e strategie di testing — piuttosto che su definizioni memorizzate

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Tag

#dbt
#data-analytics
#sql
#data-modeling
#interview

Condividi

Articoli correlati