# 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. - Published: 2026-05-25 - Updated: 2026-05-27 - Author: SharpSkill - Tags: dbt, data-engineering, data-transformation, testing, interview, analytics-engineering, sql - Reading time: 10 min --- 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](https://docs.getdbt.com/best-practices/how-we-structure/1-guide-overview), 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](https://docs.getdbt.com/docs/build/materializations) 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. ## 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](https://docs.getdbt.com/docs/dbt-versions/cloud-release-tracks), 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](https://docs.getdbt.com/docs/build/jinja-macros). 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](/technologies/data-engineering). **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](/blog/data-engineering/data-engineering-interview-questions-2026), incluyendo temas como la [arquitectura de pipelines ETL vs ELT](/blog/data-engineering/etl-vs-elt-data-pipeline-architecture), los módulos de práctica de SharpSkill sobre [fundamentos de dbt](/technologies/data-engineering/interview-questions/dbt-fundamentals-de) y [patrones avanzados de dbt](/technologies/data-engineering/interview-questions/dbt-advanced-de) cubren estos conceptos con ejercicios interactivos. ## 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 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/es/blog/data-engineering/dbt-data-transformations-testing-interview-2026