MERGE é um comando DML (Data Manipulation Language), assim como INSERT, DELETE e UPDATE. Apesar de não ser tão conhecido e usado quanto os outros DML’s, o MERGE merece uma atenção especial por ser um comando muito útil em vários tipos de casos, como sincronização de dados entre diferentes tabelas, carga de dados em processos ETL, entre outros.

Vamos para a parte prática, pois acredito que esta seja a maneira mais fácil de entender esta funcionalidade e de aprender como funciona.

Primeiro vou conectar ao schema HR e criar uma tabela para fazer os testes.

D:>sqlplus hr/hr

SQL> CREATE TABLE moto2 AS
  2  SELECT * FROM moto
  3  WHERE 1=0;

Tabela criada.

Criei uma tabela chamada “moto2”, com a mesma estrutura da tabela “moto”, que é uma tabela muito simples, conforme podem conferir abaixo:

SQL> SELECT * FROM moto;

   MOTO_ID MOTO_NOME                                           DONO
---------- --------------------------------------------- ----------
         1 Hornet                                               100
         2 CBR 1000                                             100
         3 R1                                                   100
         4 CG125                                                100
         5 CG150                                                100
         6 CB300                                                100
         7 Fazer 600                                            100

7 linhas selecionadas.

Agora vamos aos comandos MERGE!

SQL> MERGE INTO moto2 a
  2    USING moto b
  3      ON (a.moto_id = b.moto_id)
  4    WHEN MATCHED THEN
  5      UPDATE SET a.dono = b.dono
  6    WHEN NOT MATCHED THEN
  7      INSERT (moto_id, moto_nome, dono)
  8      VALUES (b.moto_id, b.moto_nome, b.dono);

7 linhas intercaladas.

O que fez o comando acima? Vamos para a “tradução”!

O comando MERGE foi aplicado na tabela “moto2“, usando como base a tabela “moto“. A chave de comparação entre as duas tabelas foi o campo “moto_id“, que é a chave primária das duas tabelas. Isso foi definido nas cláusulas USING e ON, respectivamente.

A cláusula WHEN MATCHED THEN disse o seguinte: “sempre que encontrar um registro na tabela moto em que a chave primária já exista na tabela moto2, atualize o campo dono da tabela moto2 com o valor do campo dono da tabela moto.”

A cláusula WHEN NOT MATCHED THEN disse o seguinte: “se um registro da tabela moto não foi encontrado na tabela moto2, tomando como base o campo moto_id, então insira o registro correspondente na tabela moto2“.

O exemplo acima foi bem simples. Após o comando, a tabela moto2, que antes estava vazia, ficou idêntica a tabela moto:

SQL> SELECT *
  2  FROM moto2;

   MOTO_ID MOTO_NOME                                             DONO
---------- ----------------------------------------------- ----------
         1 Hornet                                                 100
         2 CBR 1000                                               100
         3 R1                                                     100
         4 CG125                                                  100
         5 CG150                                                  100
         6 CB300                                                  100
         7 Fazer 600                                              100

7 linhas selecionadas.

Você pode estar se perguntando: fiz esse comando enorme apenas para deixar as tabelas iguais? Calma! Como a tabela moto2 estava vazia, sim, ele fez isso. Usando o mesmo comando MERGE novamente, ele fará as alterações de forma incremental. Vamos pra mais um exemplo, na sequência do que fizemos acima:

SQL> UPDATE moto
  2  SET dono = 101
  3  WHERE moto_id = 6;
1 linha atualizada.

SQL> INSERT INTO moto
  2  (moto_id, moto_nome, dono)
  3  VALUES
  4  (8, 'Ninja 1000', 102);
1 linha criada.

SQL> commit;
Commit concluído.

Alteramos a tabela moto, agora vamos consultar os dados das 2 tabelas, para ver as diferenças:

SQL> SELECT * FROM moto;

   MOTO_ID MOTO_NOME                                             DONO
---------- ----------------------------------------------- ----------
         1 Hornet                                                 100
         2 CBR 1000                                               100
         3 R1                                                     100
         4 CG125                                                  100
         5 CG150                                                  100
         6 CB300                                                  101
         7 Fazer 600                                              100
         8 Ninja 1000                                             102
8 linhas selecionadas.

SQL> SELECT * FROM moto2;

   MOTO_ID MOTO_NOME                                             DONO
---------- ----------------------------------------------- ----------
         1 Hornet                                                 100
         2 CBR 1000                                               100
         3 R1                                                     100
         4 CG125                                                  100
         5 CG150                                                  100
         6 CB300                                                  100
         7 Fazer 600                                              100
7 linhas selecionadas.

A diferença das duas tabelas são apenas 2 registros: o de moto_id = 6, onde o campo “dono” está diferente, e o moto_id = 8, que não existe na tabela moto2. Agora vamos rodar o MERGE novamente:

SQL> MERGE INTO moto2 a
  2    USING moto b
  3      ON (a.moto_id = b.moto_id)
  4    WHEN MATCHED THEN
  5      UPDATE SET a.dono = b.dono
  6    WHEN NOT MATCHED THEN
  7      INSERT (moto_id, moto_nome, dono)
  8      VALUES (b.moto_id, b.moto_nome, b.dono);

8 linhas intercaladas.

SQL> commit;

Commit concluído.

SQL> SELECT * FROM moto2;

   MOTO_ID MOTO_NOME                                             DONO
---------- ----------------------------------------------- ----------
         1 Hornet                                                 100
         2 CBR 1000                                               100
         3 R1                                                     100
         4 CG125                                                  100
         5 CG150                                                  100
         6 CB300                                                  101
         7 Fazer 600                                              100
         8 Ninja 1000                                             102

8 linhas selecionadas.

O comando MERGE atualizou os dados da tabela moto2 conforme o especificado, ou seja, o registro que não existia foi inserido. E o registro que estava diferente foi alterado. Importante ver que o comando só especificou UPDATE no campo dono, portanto, se eu alterar o campo moto_nome na tabela moto, essa alteração não será refletida na tabela moto2 com o comando MERGE.

Outra cláusula que pode ser usada é a DELETE. Vamos preparar o caso para testar essa cláusula:

SQL> UPDATE moto
  2  SET dono = null
  3  WHERE moto_id = 7;

1 linha atualizada.

SQL> INSERT INTO moto
  2  (moto_id, moto_nome, dono)
  3  VALUES
  4  (9, 'Ninja 1000', 102);

1 linha criada.

SQL> UPDATE moto
  2  SET dono = 103
  3  WHERE moto_id = 5;

1 linha atualizada.

Conferindo novamente os dados das duas tabelas:

SQL> SELECT * FROM moto;

   MOTO_ID MOTO_NOME                                             DONO
---------- ----------------------------------------------- ----------
         1 Hornet                                                 100
         2 CBR 1000                                               100
         3 R1                                                     100
         4 CG125                                                  100
         5 CG150                                                  103
         6 CB300                                                  101
         7 Fazer 600
         8 Ninja 1000                                             102
         9 Ninja 1000                                             102

9 linhas selecionadas.

SQL> SELECT * FROM moto2;

   MOTO_ID MOTO_NOME                                             DONO
---------- ----------------------------------------------- ----------
         1 Hornet                                                 100
         2 CBR 1000                                               100
         3 R1                                                     100
         4 CG125                                                  100
         5 CG150                                                  100
         6 CB300                                                  101
         7 Fazer 600                                              100
         8 Ninja 1000                                             102

8 linhas selecionadas.

E finalmente o comando MERGE usando a cláusula DELETE:

SQL> MERGE INTO moto2 a
  2    USING moto b
  3      ON (a.moto_id = b.moto_id)
  4    WHEN MATCHED THEN
  5      UPDATE SET a.dono = b.dono
  6      WHERE  b.dono IS NOT NULL
  7    DELETE WHERE (b.dono = 102);

7 linhas intercaladas.

SQL> SELECT * FROM moto2;

   MOTO_ID MOTO_NOME                                             DONO
---------- ----------------------------------------------- ----------
         1 Hornet                                                 100
         2 CBR 1000                                               100
         3 R1                                                     100
         4 CG125                                                  100
         5 CG150                                                  103
         6 CB300                                                  101
         7 Fazer 600                                              100

7 linhas selecionadas.

O MERGE atualizou o registro 5, atualizando o campo dono para o valor 103, e também apagou os registros 8 e 9, obedecendo a condição especificada (dono = 102).