Cómo hacer un upsert con MERGE en una tabla Delta (Lakehouse)
El upsert es la operación que, de una sola vez, actualiza las filas que ya existen e inserta las que son nuevas. En una tabla Delta del Lakehouse, el comando MERGE hace exactamente esto de forma atómica: evita duplicados y mantiene la tabla consistente aunque los datos de origen lleguen por lotes. Por eso es la base de cualquier carga incremental fiable, muy usada para actualizar dimensiones y aplicar cambios procedentes de un sistema de origen.
Requisitos previos
- Un workspace con capacidad Microsoft Fabric y un Lakehouse creado.
- Un notebook de Fabric conectado a ese Lakehouse.
- Una tabla Delta de destino (por ejemplo,
dim_clientes) o ganas de crear una. - Conocimientos básicos de SQL o PySpark.
Paso 1: Preparar la tabla de destino
El upsert necesita una tabla Delta de destino. Si aún no la tienes, crea una pequeña tabla de ejemplo. En el Lakehouse las tablas son Delta por defecto, pero puedes indicarlo de forma explícita con USING DELTA. El IF NOT EXISTS hace que el paso sea seguro de repetir, sin borrar datos que ya existan.
CREATE TABLE IF NOT EXISTS dim_clientes (
cliente_id INT,
nome STRING,
cidade STRING
) USING DELTA;
Paso 2: Crear el origen con los datos nuevos
El origen es el lote con las filas nuevas y las modificadas. Para el ejemplo, crea un DataFrame y regístralo como vista temporal para poder referenciarlo en SQL. Fíjate en que los clientes 1 y 2 servirán para actualizar y el 3 es nuevo, para insertar.
from pyspark.sql import Row
origem = spark.createDataFrame([
Row(cliente_id=1, nome="Ana Silva", cidade="Porto"),
Row(cliente_id=2, nome="Bruno Costa", cidade="Lisboa"),
Row(cliente_id=3, nome="Carla Dias", cidade="Braga"),
])
origem.createOrReplaceTempView("origem_clientes")
Paso 3: Escribir el MERGE en SQL
El MERGE compara el destino con el origen mediante una clave. Cuando hay coincidencia (WHEN MATCHED) actualiza la fila; cuando no la hay (WHEN NOT MATCHED) inserta una nueva. Todo ocurre en una única transacción, así que quien esté leyendo la tabla nunca ve un estado a medias. Esta es la forma más legible de escribir un upsert.
MERGE INTO dim_clientes AS destino
USING origem_clientes AS origem
ON destino.cliente_id = origem.cliente_id
WHEN MATCHED THEN
UPDATE SET destino.nome = origem.nome,
destino.cidade = origem.cidade
WHEN NOT MATCHED THEN
INSERT (cliente_id, nome, cidade)
VALUES (origem.cliente_id, origem.nome, origem.cidade);
Consejo: la clave usada en el ON debe ser única en el origen. Si hay ids repetidos, el MERGE devuelve el error "multiple source rows matched". Elimina los duplicados antes de ejecutar el comando.
Paso 4: La alternativa en PySpark (DeltaTable)
Si prefieres Python, la API DeltaTable hace el mismo upsert sin escribir SQL. Los métodos whenMatchedUpdateAll y whenNotMatchedInsertAll son atajos útiles cuando las columnas del origen y del destino coinciden; si necesitas un control fino, usa whenMatchedUpdate e indica solo las columnas a cambiar.
from delta.tables import DeltaTable
destino = DeltaTable.forName(spark, "dim_clientes")
(destino.alias("destino")
.merge(origem.alias("origem"),
"destino.cliente_id = origem.cliente_id")
.whenMatchedUpdateAll()
.whenNotMatchedInsertAll()
.execute())
Verificar el resultado
Consulta la tabla y confirma que el cliente 3 se insertó y que los clientes 1 y 2 tienen ahora los valores más recientes, sin filas duplicadas. Si cuentas las filas, deberías tener exactamente tres.
SELECT cliente_id, nome, cidade
FROM dim_clientes
ORDER BY cliente_id;
Para confirmar que el MERGE se registró como una nueva versión de la tabla Delta, ejecuta DESCRIBE HISTORY dim_clientes y busca la operación MERGE en la columna operation.
Conclusión
Con el comando MERGE ya puedes hacer upserts fiables en una tabla Delta del Lakehouse, la base de cualquier carga incremental. A continuación, prueba a añadir una condición como WHEN MATCHED AND destino.cidade <> origem.cidade para actualizar solo cuando algo cambia de verdad, o usa una columna de fecha para procesar solo los registros más recientes. ¿Cuál será la primera tabla de tu Lakehouse en pasar a un upsert con MERGE?