Cómo hacer upsert en una tabla Delta en Databricks (MERGE)
Actualizar los registros que ya existen e insertar los que son nuevos, todo en una única operación atómica: eso es exactamente lo que hace el comando MERGE sobre una tabla Delta. En lugar de borrar y reescribir la tabla entera, MERGE compara un origen con el destino mediante una clave y aplica solo los cambios necesarios — el llamado upsert. Es la forma correcta de mantener una tabla Delta sincronizada en Databricks sin duplicar datos ni ejecutar pipelines pesados.
Requisitos previos
- Un workspace de Databricks con acceso a un cluster o SQL warehouse activo.
- Permisos para crear y escribir tablas en el catálogo (Unity Catalog o hive_metastore).
- Conocimientos básicos de SQL o de PySpark (DataFrames).
- Saber qué columna clave identifica de forma única cada registro (por ejemplo, un id).
Paso 1: Crear una tabla Delta de destino
Empieza creando la tabla que vas a mantener actualizada con el tiempo. En Databricks, cualquier tabla gestionada usa el formato Delta de forma predeterminada, lo que le da transacciones ACID — y eso es precisamente lo que hace que MERGE sea seguro. Ejecuta este SQL en una celda de notebook:
CREATE TABLE clientes (
id INT,
nome STRING,
cidade STRING
) USING DELTA;
INSERT INTO clientes VALUES
(1, 'Ana', 'Lisboa'),
(2, 'Bruno', 'Porto');
Ya tienes dos clientes en la tabla de destino. Es sobre esta tabla sobre la que actuará MERGE, comparándola con los datos nuevos que preparas a continuación.
Paso 2: Preparar el origen con los datos nuevos
El origen contiene los cambios que quieres aplicar y puede ser una tabla, una view o un DataFrame. En este ejemplo, el cliente 2 ha cambiado de ciudad y el cliente 3 es completamente nuevo. Para simplificar, crea una view temporal como origen:
CREATE OR REPLACE TEMP VIEW clientes_novos AS
SELECT * FROM VALUES
(2, 'Bruno', 'Coimbra'),
(3, 'Carla', 'Braga')
AS t(id, nome, cidade);
Fíjate en que la columna id es la clave que une las dos tablas: el id 2 ya existe en el destino (se actualizará) y el id 3 no existe (se insertará). Elegir bien esta clave es la parte más importante de todo el proceso.
Paso 3: Ejecutar el MERGE en SQL
Llegamos al paso central. MERGE recorre el origen fila a fila y, para cada una, decide qué hacer según la condición ON que compara las claves:
MERGE INTO clientes AS destino
USING clientes_novos AS origem
ON destino.id = origem.id
WHEN MATCHED THEN
UPDATE SET destino.cidade = origem.cidade
WHEN NOT MATCHED THEN
INSERT (id, nome, cidade)
VALUES (origem.id, origem.nome, origem.cidade);
Se lee casi de forma literal: cuando el id del origen coincide (MATCHED) con un id ya presente en el destino, actualiza la ciudad; cuando no coincide (NOT MATCHED), inserta un registro nuevo. Lo más importante es que todo ocurre en una única transacción atómica — o se ejecuta por completo, o no cambia nada, aunque el cluster falle a mitad.
Consejo: la condición ON debe usar siempre una clave única. Si el origen tiene ids repetidos que coinciden con la misma fila de destino, MERGE falla a propósito, para evitar resultados ambiguos.
Paso 4: Hacer lo mismo en PySpark (opcional)
Si prefieres trabajar en Python, la API DeltaTable hace exactamente lo mismo con una sintaxis encadenada. Es la opción natural cuando el origen ya es un DataFrame que proviene de otro proceso de transformación:
from delta.tables import DeltaTable
destino = DeltaTable.forName(spark, "clientes")
origem = spark.createDataFrame(
[(2, "Bruno", "Coimbra"), (3, "Carla", "Braga")],
["id", "nome", "cidade"],
)
(destino.alias("d")
.merge(origem.alias("o"), "d.id = o.id")
.whenMatchedUpdate(set={"cidade": "o.cidade"})
.whenNotMatchedInsertAll()
.execute())
El método whenNotMatchedInsertAll() inserta todas las columnas automáticamente cuando los nombres coinciden entre origen y destino, ahorrándote listarlas una a una. Tanto SQL como PySpark producen el mismo resultado — usa el que sea más cómodo para tu equipo.
Verificar el resultado
Consulta la tabla para confirmar que el upsert se ejecutó como esperabas:
SELECT * FROM clientes ORDER BY id;
Deberías ver tres filas: el cliente 1 sin cambios, el cliente 2 con la ciudad actualizada a Coimbra y el cliente 3 (Carla) recién insertado. Para confirmar el historial de la operación, ejecuta DESCRIBE HISTORY clientes y verás una entrada MERGE con el número de filas insertadas y actualizadas.
Conclusión
Con un único MERGE has mantenido la tabla Delta sincronizada, sin borrar datos ni arriesgarte a duplicados — la base de cualquier pipeline incremental en Databricks. El siguiente paso natural es conectar el origen a datos reales, como un archivo que llega cada día, y programar el MERGE en un Databricks Workflow. Un consejo final: añade una cláusula WHEN MATCHED AND ... THEN DELETE si también necesitas eliminar registros que ya no existen en el origen. ¿Qué otra regla de sincronización tendría sentido en tu caso?