(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como fazer upsert numa tabela Delta no Databricks (MERGE)

João Barros 05 de July de 2026 4 min de leitura

Atualizar os registos que já existem e inserir os que são novos, tudo numa única operação atómica: é exatamente isto que o comando MERGE faz numa tabela Delta. Em vez de apagar e reescrever a tabela inteira, o MERGE compara uma origem com o destino através de uma chave e aplica apenas as alterações necessárias — o chamado upsert. É a forma correta de manter uma tabela Delta sincronizada no Databricks sem duplicar dados nem correr pipelines pesados.

Pré-requisitos

  • Um workspace Databricks com acesso a um cluster ou SQL warehouse ativo.
  • Permissões para criar e escrever tabelas no catálogo (Unity Catalog ou hive_metastore).
  • Conhecimentos básicos de SQL ou de PySpark (DataFrames).
  • Saber qual é a coluna-chave que identifica cada registo de forma única (por exemplo, um id).

Passo 1: Criar uma tabela Delta de destino

Começa por criar a tabela que vais manter atualizada ao longo do tempo. No Databricks, qualquer tabela gerida usa o formato Delta por omissão, o que lhe dá transações ACID — e é precisamente isso que torna o MERGE seguro. Corre este SQL numa célula de notebook:

CREATE TABLE clientes (
  id INT,
  nome STRING,
  cidade STRING
) USING DELTA;

INSERT INTO clientes VALUES
  (1, 'Ana', 'Lisboa'),
  (2, 'Bruno', 'Porto');

Ficaste com dois clientes na tabela de destino. É sobre esta tabela que o MERGE vai atuar, comparando-a com os dados novos que preparas a seguir.

Passo 2: Preparar a origem com os dados novos

A origem contém as alterações que queres aplicar e pode ser uma tabela, uma view ou um DataFrame. Neste exemplo, o cliente 2 mudou de cidade e o cliente 3 é completamente novo. Para simplificar, cria uma view temporária como origem:

CREATE OR REPLACE TEMP VIEW clientes_novos AS
SELECT * FROM VALUES
  (2, 'Bruno', 'Coimbra'),
  (3, 'Carla', 'Braga')
AS t(id, nome, cidade);

Repara que a coluna id é a chave que liga as duas tabelas: o id 2 já existe no destino (vai ser atualizado) e o id 3 não existe (vai ser inserido). Escolher bem esta chave é o passo mais importante de todo o processo.

Passo 3: Executar o MERGE em SQL

Chegámos ao passo central. O MERGE percorre a origem linha a linha e, para cada uma, decide o que fazer com base na condição ON que compara as chaves:

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);

Lê-se de forma quase literal: quando o id da origem corresponde (MATCHED) a um id já presente no destino, atualiza a cidade; quando não corresponde (NOT MATCHED), insere um registo novo. O mais importante é que tudo acontece numa só transação atómica — ou corre por completo, ou não altera nada, mesmo que o cluster falhe a meio.

Dica: a condição ON deve usar sempre uma chave única. Se a origem tiver ids repetidos que correspondam à mesma linha de destino, o MERGE falha de propósito, para evitar resultados ambíguos.

Passo 4: Fazer o mesmo em PySpark (opcional)

Se preferes trabalhar em Python, a API DeltaTable faz exatamente o mesmo com uma sintaxe encadeada. É a opção natural quando a origem já é um DataFrame que resulta de outro processo de transformação:

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())

O método whenNotMatchedInsertAll() insere todas as colunas automaticamente quando os nomes coincidem entre origem e destino, poupando-te de as listar uma a uma. Tanto o SQL como o PySpark produzem o mesmo resultado — usa o que for mais confortável para a tua equipa.

Verificar o resultado

Consulta a tabela para confirmar que o upsert correu como esperado:

SELECT * FROM clientes ORDER BY id;

Deves ver três linhas: o cliente 1 inalterado, o cliente 2 com a cidade atualizada para Coimbra e o cliente 3 (Carla) recém-inserido. Para confirmar o histórico da operação, corre DESCRIBE HISTORY clientes e vais ver uma entrada do tipo MERGE com o número de linhas inseridas e atualizadas.

Conclusão

Com um único MERGE mantiveste a tabela Delta sincronizada, sem apagar dados nem correr o risco de duplicados — a base de qualquer pipeline incremental no Databricks. O próximo passo natural é ligar a origem a dados reais, como um ficheiro que chega todos os dias, e agendar o MERGE num Databricks Workflow. Uma dica final: acrescenta uma cláusula WHEN MATCHED AND ... THEN DELETE se precisares de remover registos que já não existem na origem. Que outra regra de sincronização faria sentido no teu caso?