dbt en 2026: transformaciones de datos, pruebas y preguntas de entrevista

Tutorial práctico de dbt (data build tool): transformaciones SQL, modelado por capas, estrategias de pruebas y preguntas reales de entrevista para roles de data engineering en 2026.

Tutorial de dbt data build tool transformaciones y pruebas de datos 2026

dbt (data build tool) se convirtió en el framework estándar para transformar datos dentro de los almacenes modernos, usado en producción por más de 40 000 empresas en 2026. Este tutorial cubre los mecanismos centrales de las transformaciones de dbt, las estrategias de pruebas y las preguntas que realmente surgen en las entrevistas de data engineering.

Qué hace dbt realmente

dbt maneja la T en ELT. Compila sentencias SQL SELECT en DDL (CREATE TABLE, CREATE VIEW, MERGE) y las ejecuta contra un almacén — Snowflake, BigQuery, Redshift o Databricks. El control de versiones, la resolución de dependencias, las pruebas y la documentación vienen integrados.

Modelado por capas: staging, intermedio y marts

Un proyecto dbt bien estructurado separa las transformaciones en tres capas. Este enfoque, popularizado por la comunidad de dbt, impone modelos de responsabilidad única y facilita la depuración.

Los modelos de staging están más cerca de los datos crudos. Su tarea es acotada: renombrar columnas, convertir tipos y filtrar filas basura. Sin uniones, sin agregaciones.

sql
-- models/staging/stg_orders.sql
WITH source AS (
    SELECT * FROM {{ source('ecommerce', 'raw_orders') }}
)
SELECT
    id AS order_id,
    customer_id,
    CAST(order_date AS DATE) AS order_date,
    CAST(amount AS DECIMAL(10, 2)) AS order_amount,
    LOWER(status) AS order_status
FROM source
WHERE id IS NOT NULL

Los modelos intermedios aplican lógica de negocio — uniones, agregaciones, funciones de ventana. Referencian los modelos de staging mediante ref(), que registra las dependencias en el DAG.

sql
-- models/intermediate/int_customer_orders.sql
WITH orders AS (
    SELECT * FROM {{ ref('stg_orders') }}
),
customers AS (
    SELECT * FROM {{ ref('stg_customers') }}
)
SELECT
    c.customer_id,
    c.customer_name,
    COUNT(o.order_id) AS total_orders,
    SUM(o.order_amount) AS lifetime_value,
    MIN(o.order_date) AS first_order_date,
    MAX(o.order_date) AS last_order_date
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name

Los marts son la capa final de consumo — tablas limpias y documentadas que los tableros y analistas consultan directamente.

Este enfoque por capas significa que una fuente rota solo afecta al staging, no a todo el pipeline. Cada capa puede probarse de forma independiente.

La función ref() y la resolución del DAG

ref() no es un alias. Llamar a {{ ref('stg_orders') }} hace dos cosas: resuelve el nombre de tabla completamente calificado en tiempo de compilación y registra una arista de dependencia en el grafo acíclico dirigido (DAG) de dbt. Sin ref(), dbt no tiene forma de determinar el orden de ejecución.

Un error común es codificar a mano los nombres de tabla en lugar de usar ref(). Esto rompe el seguimiento de dependencias y puede provocar que los modelos se ejecuten antes de que sus dependencias previas estén listas.

sql
-- Malo: referencia codificada a mano, sin seguimiento de dependencias
SELECT * FROM analytics.stg_orders

-- Bueno: ref() registra la dependencia
SELECT * FROM {{ ref('stg_orders') }}

El DAG también impulsa funciones como dbt run --select stg_orders+, que ejecuta un modelo y todo lo que está aguas abajo de él — útil para reconstrucciones dirigidas tras un cambio de esquema en la fuente.

Materializaciones: elegir la estrategia de almacenamiento adecuada

dbt ofrece cuatro materializaciones integradas, cada una adecuada para distintos patrones de acceso y volúmenes de datos.

| Materialización | Almacenamiento | Ideal para | Compensación | |----------------|---------|----------|----------| | view | Sin almacenamiento (calculada al leer) | Transformaciones ligeras, conjuntos pequeños | Lecturas lentas en datos grandes | | table | Reconstrucción completa en cada ejecución | Modelos de capa mart, lecturas rápidas | Reconstruye todo, mayor costo | | incremental | Solo agrega/fusiona filas nuevas | Tablas de hechos grandes, flujos de eventos | Lógica más compleja, requiere unique_key | | ephemeral | Insertada como CTE, nunca materializada | Lógica reutilizable compartida entre modelos | No consultable directamente |

El valor predeterminado es view. Se sobrescribe en el bloque de config del modelo o en dbt_project.yml:

sql
-- models/marts/fct_daily_revenue.sql
{{
    config(
        materialized='incremental',
        unique_key='revenue_date',
        incremental_strategy='merge'
    )
}}
SELECT
    DATE(order_date) AS revenue_date,
    SUM(order_amount) AS daily_revenue,
    COUNT(DISTINCT customer_id) AS unique_customers
FROM {{ ref('stg_orders') }}
WHERE order_status = 'completed'
{% if is_incremental() %}
    AND order_date > (SELECT MAX(revenue_date) FROM {{ this }})
{% endif %}
GROUP BY DATE(order_date)

El bloque is_incremental() solo se ejecuta durante las construcciones incrementales — en una recarga completa (dbt run --full-refresh) se omite y la tabla entera se reconstruye.

¿Listo para aprobar tus entrevistas de Data Engineering?

Practica con nuestros simuladores interactivos, flashcards y tests técnicos.

Probar la calidad de los datos en cada capa

dbt provee dos categorías de pruebas: pruebas genéricas declaradas en YAML y pruebas singulares escritas como archivos SQL independientes que devuelven filas cuando fallan.

Las pruebas genéricas cubren restricciones estructurales:

yaml
# models/staging/_stg_models.yml
version: 2

models:
  - name: stg_orders
    columns:
      - name: order_id
        tests:
          - unique           # Sin IDs de pedido duplicados
          - not_null         # Cada fila tiene un ID de pedido
      - name: order_status
        tests:
          - accepted_values:
              values: ['completed', 'pending', 'cancelled', 'refunded']
      - name: customer_id
        tests:
          - not_null
          - relationships:   # Verificación de integridad referencial
              to: ref('stg_customers')
              field: customer_id

Las pruebas singulares validan reglas de negocio que las genéricas no pueden expresar:

sql
-- tests/assert_revenue_never_negative.sql
-- Devuelve filas donde el ingreso diario es negativo (debería devolver 0 filas)
SELECT
    revenue_date,
    daily_revenue
FROM {{ ref('fct_daily_revenue') }}
WHERE daily_revenue < 0

Las pruebas unitarias, introducidas en dbt 1.8, validan la lógica de transformación con entradas controladas y salidas esperadas — sin necesidad de un almacén. Se ejecutan directamente en la fase de pruebas de dbt.

La estrategia de pruebas debe seguir el flujo de datos: chequeos de frescura y validaciones de conteo de filas a nivel de fuente, pruebas de esquema a nivel de staging (not_null, unique), integridad referencial a nivel intermedio y aserciones de lógica de negocio a nivel de mart.

dbt Core v1.10 y el motor Fusion

dbt Core v1.10 introdujo el flag --sample para los comandos run y build. Este flag aplica un muestreo basado en tiempo a ref() y source(), permitiendo a los desarrolladores validar transformaciones sobre un subconjunto de datos sin el costo de una construcción completa. Útil para iterar sobre modelos respaldados por tablas de hechos de miles de millones de filas.

El motor dbt Fusion, una reescritura desde cero en Rust, ahora es el valor predeterminado para los proyectos nuevos en dbt Cloud sobre Snowflake, BigQuery, Redshift y Databricks. Fusion introduce versionado semántico a partir de la 2.0 y trae mejoras de rendimiento significativas a la compilación y la ejecución.

Otras incorporaciones notables de 2026: la especificación YAML del Semantic Layer para definiciones de métricas centralizadas, Cost Insights (beta) para estimar el cómputo del almacén por modelo, y los paquetes privados nativos ahora en disponibilidad general.

Macros y Jinja para lógica reutilizable

Cuando el mismo patrón SQL aparece en varios modelos, conviene extraerlo a una macro. Las macros son funciones Jinja almacenadas en el directorio macros/.

sql
-- macros/cents_to_dollars.sql
{% macro cents_to_dollars(column_name) %}
    ROUND(CAST({{ column_name }} AS DECIMAL(10, 4)) / 100, 2)
{% endmacro %}

Llamada en cualquier modelo:

sql
-- models/staging/stg_payments.sql
SELECT
    payment_id,
    order_id,
    {{ cents_to_dollars('amount_cents') }} AS amount_dollars,
    payment_method
FROM {{ source('stripe', 'payments') }}

Esto mantiene el código DRY. La alternativa — copiar la fórmula de conversión en cada modelo que la necesita — genera carga de mantenimiento e inconsistencias.

Preguntas de entrevista que realmente se hacen

Las entrevistas de data engineering en 2026 evalúan cada vez más el conocimiento de dbt más allá de lo básico. Estas son las preguntas que diferencian a los candidatos, extraídas de patrones vistos en roles de empresas que usan stacks de datos modernos.

P: Un modelo incremental reprocesó toda la tabla durante la noche. ¿Qué pasó?

La causa más común: la columna unique_key contenía valores nulos. Cuando dbt intenta un MERGE sobre una clave nula, la coincidencia falla para cada fila, por lo que inserta duplicados. La segunda causa: alguien ejecutó dbt run --full-refresh sin darse cuenta de que reconstruye la tabla desde cero. La tercera: el filtro is_incremental() referenciaba una columna que aún no existe en la tabla destino (primera ejecución vs. ejecuciones posteriores). La depuración empieza por revisar el SQL compilado en target/compiled/.

P: ¿Cómo deben estructurarse las pruebas por capas en un proyecto dbt de producción?

Los chequeos de frescura de la fuente se ejecutan primero — si la fuente no se actualizó, los modelos aguas abajo no deberían correr sobre datos obsoletos. Las pruebas de staging validan restricciones de esquema: claves primarias (unique + not_null), valores aceptados y conversiones de tipo. Las pruebas intermedias verifican la integridad referencial a través de las uniones. Las pruebas de mart afirman invariantes de negocio: ingreso >= 0, usuarios activos >= usuarios de pago, y la suma de las partes igual al total. Todas las pruebas corren en CI sobre los pull requests contra un esquema de dev, y luego nuevamente tras el despliegue en producción con alertas.

P: ¿Cuándo debe ser un modelo efímero en lugar de una vista?

Los modelos efímeros insertan su SQL como CTE dentro de los modelos consumidores — útil para lógica reutilizable que no necesita consultarse de forma independiente. Las vistas se calculan al leer y existen como objetos consultables. La compensación: los modelos efímeros no pueden probarse directamente (no tienen tabla sobre la cual ejecutar aserciones) ni aparecer en herramientas de linaje de datos. Usar efímeros para lógica auxiliar interna; usar vistas para todo lo que necesite pruebas o monitoreo independiente.

P: Explicar la diferencia entre source() y ref().

source() apunta a tablas crudas definidas en un archivo sources.yml — son tablas que dbt no gestiona. ref() apunta a otros modelos dbt. Ambos registran dependencias en el DAG, pero source() además habilita los chequeos de frescura (dbt source freshness), que ref() no hace. Usar source() para tablas crudas y ref() para todo lo demás no es opcional — es la forma en que dbt sabe qué controla y qué no.

Para un conjunto más amplio de preguntas de entrevista de data engineering, incluyendo temas como la arquitectura de pipelines ETL vs ELT, los módulos de práctica de SharpSkill sobre fundamentos de dbt y patrones avanzados de dbt cubren estos conceptos con ejercicios interactivos.

¡Empieza a practicar!

Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.

Conclusión

  • dbt transforma los datos crudos del almacén mediante sentencias SQL SELECT, compiladas automáticamente en DDL — la estructura por capas staging/intermedio/mart mantiene cada modelo enfocado en una sola responsabilidad
  • La función ref() es la columna vertebral de la gestión de dependencias: resuelve los nombres de tabla y construye el DAG que controla el orden de ejecución
  • Las materializaciones incrementales reducen el costo en tablas grandes, pero requieren un manejo cuidadoso de unique_key, los valores nulos y el filtro is_incremental()
  • Las pruebas deben seguir el flujo de datos — frescura de la fuente, restricciones de esquema en staging, integridad referencial en el intermedio, aserciones de lógica de negocio a nivel de mart
  • dbt Core v1.10 trae el flag --sample para una iteración más rápida, mientras que el motor Fusion (basado en Rust, versión 2.0) ahora es el valor predeterminado en dbt Cloud
  • Las preguntas de entrevista sobre dbt se centran en depurar fallas reales (reprocesamiento incremental, claves nulas, fuentes obsoletas) en lugar de definiciones — la experiencia práctica con SQL compilado y pipelines de CI importa más que las respuestas memorizadas

¡Empieza a practicar!

Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.

Etiquetas

#dbt
#data-engineering
#data-transformation
#testing
#interview
#analytics-engineering
#sql

Compartir

Artículos relacionados