MERGE¶
Insere, atualiza e exclui os valores em uma tabela baseada em valores em uma segunda tabela ou em uma subconsulta. Isto pode ser útil se a segunda tabela for um log de alterações que contenha novas linhas (a serem inseridas), linhas modificadas (a serem atualizadas) e/ou linhas marcadas (a serem excluídas) na tabela de destino.
O comando oferece suporte à semântica para o tratamento dos seguintes casos:
- Valores correspondentes (para atualizações e exclusões). 
- Valores não correspondentes (para inserções). 
Sintaxe¶
MERGE INTO <target_table> USING <source> ON <join_expr> { matchedClause | notMatchedClause } [ ... ]
Onde:
matchedClause ::= WHEN MATCHED [ AND <case_predicate> ] THEN { UPDATE SET <col_name> = <expr> [ , <col_name2> = <expr2> ... ] | DELETE } [ ... ]notMatchedClause ::= WHEN NOT MATCHED [ AND <case_predicate> ] THEN INSERT [ ( <col_name> [ , ... ] ) ] VALUES ( <expr> [ , ... ] )
Parâmetros¶
- target_table
- Especifica a tabela a ser fundida. 
- source
- Especifica a tabela ou subconsulta a ser unida à tabela de destino. 
- join_expr
- Especifica a expressão na qual se deve unir a tabela de destino e a origem. 
matchedClause (para atualizações ou exclusões)¶
- WHEN MATCHED ... THEN UPDATE <col_name> = <expr> | DELETE
- Especifica a ação a ser executada quando os valores correspondem. 
- AND case_predicate
- Opcionalmente, especifica uma expressão que, quando verdadeira, faz com que o caso correspondente seja executado. - Padrão: sem valor (caso com correspondência é sempre executado) 
- SET col_name = expr[ … ]
- Especifica a coluna dentro da tabela de destino a ser atualizada ou inserida e a expressão correspondente para o novo valor da coluna (pode se referir tanto à relação de destino como à relação de origem). - Em uma única subcláusula - SET, você pode especificar várias colunas para atualização/exclusão.
notMatchedClause (para inserções)¶
- WHEN NOT MATCHED ... THEN INSERT
- Especifica a ação a ser executada quando os valores não são correspondentes. 
- AND case_predicate
- Opcionalmente, especifica uma expressão que, quando verdadeira, faz com que o caso não correspondente seja executado. - Padrão: sem valor (caso sem correspondência é sempre executado) 
- ( col_name [ , ... ] )
- Opcionalmente, especifica uma ou mais colunas dentro da tabela de destino a ser atualizada ou inserida. - Padrão: sem valor (todas as colunas dentro da tabela de destino são atualizadas ou inseridas) 
- VALUES ( expr [ , ... ] )
- Especifica as expressões correspondentes para os valores das colunas inseridas (devem se referir às relações de origem). 
Notas de uso¶
- Uma única instrução MERGE pode incluir múltiplas cláusulas de correspondência e não correspondência (isto é, - WHEN MATCHED ...e- WHEN NOT MATCHED ...).
- Qualquer cláusula de correspondência ou não correspondência que omita a subcláusula - AND(comportamento padrão) deve ser a última cláusula do tipo na instrução (por exemplo, uma cláusula- WHEN MATCHED ...não pode ser seguida por uma cláusula- WHEN MATCHED AND ...). Isso resulta em um caso inalcançável, que retorna um erro.
Comportamento de junção duplicada¶
Resultados não determinísticos para UPDATE e DELETE¶
Quando uma junção une uma linha na tabela de destino com várias linhas na tabela de origem, as seguintes condições de junção produzem resultados não determinísticos (ou seja, o sistema não consegue determinar o valor de origem a ser usado para atualizar ou excluir a linha de destino):
- Uma linha de destino é selecionada para ser atualizada com múltiplos valores (por exemplo, - WHEN MATCHED ... THEN UPDATE).
- Uma linha de destino é selecionada para ser atualizada e excluída (por exemplo, - WHEN MATCHED ... THEN UPDATE,- WHEN MATCHED ... THEN DELETE).
Nesta situação, o resultado da fusão depende do valor especificado para o parâmetro de sessão ERROR_ON_NONDETERMINISTIC_MERGE:
- Se TRUE (valor padrão), a fusão retorna um erro. 
- Se FALSE, uma linha entre as duplicatas é selecionada para realizar a atualização ou exclusão; a linha selecionada não é definida. 
Resultados determinísticos para UPDATE e DELETE¶
As fusões determinísticas sempre se completam sem erros. Uma fusão é determinística se atender às seguintes condições para cada linha de destino:
- Uma ou mais linhas de origem satisfazem as cláusulas - WHEN MATCHED ... THEN DELETE, e nenhuma outra linha de origem satisfaz qualquer cláusula- WHEN MATCHED.- OR 
- Exatamente uma linha de origem satisfaz uma cláusula - WHEN MATCHED ... THEN UPDATE, e nenhuma outra linha de origem satisfaz qualquer cláusula- WHEN MATCHED.
Isto torna MERGE semanticamente equivalente aos comandos UPDATE e DELETE.
Nota
Para evitar erros quando múltiplas linhas na fonte de dados (isto é, a tabela ou subconsulta de origem) correspondem à tabela de destino com base na condição ON, use GROUP BY na cláusula de origem para garantir que cada linha de destino se una a uma linha (no máximo) na origem.
No exemplo a seguir, suponha que src inclua várias linhas com o mesmo valor k. É ambíguo quais valores (v) serão usados para atualizar linhas na linha de destino com o mesmo valor de k.  Ao utilizar MAX() e GROUP BY, a consulta esclarece exatamente qual valor de v de src é utilizado:
MERGE INTO target USING (select k, max(v) as v from src group by k) AS b ON target.k = b.k
  WHEN MATCHED THEN UPDATE SET target.v = b.v
  WHEN NOT MATCHED THEN INSERT (k, v) VALUES (b.k, b.v);
Resultados determinísticos para INSERT¶
As fusões determinísticas sempre se completam sem erros.
Se o MERGE contiver uma cláusula WHEN NOT MATCHED ... THEN INSERT, e se não houver linhas correspondentes no destino, e se a fonte contiver valores duplicados, então o alvo receberá uma cópia da linha para a cópia de each na fonte. (Um exemplo está incluído abaixo).
Exemplos¶
Realizar uma simples fusão:
Criar e carregar as tabelas:
CREATE TABLE target_table (ID INTEGER, description VARCHAR); CREATE TABLE source_table (ID INTEGER, description VARCHAR);INSERT INTO target_table (ID, description) VALUES (10, 'To be updated (this is the old value)') ; INSERT INTO source_table (ID, description) VALUES (10, 'To be updated (this is the new value)') ;Executar a instrução MERGE:
MERGE INTO target_table USING source_table ON target_table.id = source_table.id WHEN MATCHED THEN UPDATE SET target_table.description = source_table.description; +------------------------+ | number of rows updated | |------------------------| | 1 | +------------------------+Exibir o(s) novo(s) valor(es) na tabela de destino (a tabela de origem permanece inalterada):
SELECT * FROM target_table; +----+---------------------------------------+ | ID | DESCRIPTION | |----+---------------------------------------| | 10 | To be updated (this is the new value) | +----+---------------------------------------+ SELECT * FROM source_table; +----+---------------------------------------+ | ID | DESCRIPTION | |----+---------------------------------------| | 10 | To be updated (this is the new value) | +----+---------------------------------------+
Realizar uma fusão básica com uma mistura de operações (excluir, atualizar, inserir):
MERGE INTO t1 USING t2 ON t1.t1Key = t2.t2Key WHEN MATCHED AND t2.marked = 1 THEN DELETE WHEN MATCHED AND t2.isNewStatus = 1 THEN UPDATE SET val = t2.newVal, status = t2.newStatus WHEN MATCHED THEN UPDATE SET val = t2.newVal WHEN NOT MATCHED THEN INSERT (val, status) VALUES (t2.newVal, t2.newStatus);
Realizar uma fusão em que a origem tem valores duplicados e o destino não tem valores correspondentes. Note que todas as cópias do registro de origem são inseridas no destino:
Truncar as duas tabelas e carregar novas linhas na tabela de origem. Observe que as linhas incluem duplicatas.
TRUNCATE TABLE source_table; TRUNCATE TABLE target_table; INSERT INTO source_table (ID, description) VALUES (50, 'This is a duplicate in the source and has no match in target'), (50, 'This is a duplicate in the source and has no match in target') ;Executar a instrução MERGE:
MERGE INTO target_table USING source_table ON target_table.id = source_table.id WHEN MATCHED THEN UPDATE SET target_table.description = source_table.description WHEN NOT MATCHED THEN INSERT (ID, description) VALUES (source_table.id, source_table.description); +-------------------------+------------------------+ | number of rows inserted | number of rows updated | |-------------------------+------------------------| | 2 | 0 | +-------------------------+------------------------+Mostrar o novo valor na tabela de destino:
SELECT ID FROM target_table; +----+ | ID | |----| | 50 | | 50 | +----+
Unir registros utilizando junções que produzem resultados não determinísticos e determinísticos:
-- Setup for example. CREATE TABLE target_orig (k NUMBER, v NUMBER); INSERT INTO target_orig VALUES (0, 10); CREATE TABLE src (k NUMBER, v NUMBER); INSERT INTO src VALUES (0, 11), (0, 12), (0, 13); -- Multiple updates conflict with each other. -- If ERROR_ON_NONDETERMINISTIC_MERGE=true, returns an error; -- otherwise updates target.v with a value (e.g. 11, 12, or 13) from one of the duplicate rows (row not defined). CREATE OR REPLACE TABLE target CLONE target_orig; MERGE INTO target USING src ON target.k = src.k WHEN MATCHED THEN UPDATE SET target.v = src.v; -- Updates and deletes conflict with each other. -- If ERROR_ON_NONDETERMINISTIC_MERGE=true, returns an error; -- otherwise either deletes the row or updates target.v with a value (e.g. 12 or 13) from one of the duplicate rows (row not defined). CREATE OR REPLACE TABLE target CLONE target_orig; MERGE INTO target USING src ON target.k = src.k WHEN MATCHED AND src.v = 11 THEN DELETE WHEN MATCHED THEN UPDATE SET target.v = src.v; -- Multiple deletes do not conflict with each other; -- joined values that do not match any clause do not prevent the delete (src.v = 13). -- Merge succeeds and the target row is deleted. CREATE OR REPLACE TABLE target CLONE target_orig; MERGE INTO target USING src ON target.k = src.k WHEN MATCHED AND src.v <= 12 THEN DELETE; -- Joined values that do not match any clause do not prevent an update (src.v = 12, 13). -- Merge succeeds and the target row is set to target.v = 11. CREATE OR REPLACE TABLE target CLONE target_orig; MERGE INTO target USING src ON target.k = src.k WHEN MATCHED AND src.v = 11 THEN UPDATE SET target.v = src.v; -- Use GROUP BY in the source clause to ensure that each target row joins against one row -- in the source: CREATE OR REPLACE TABLE target CLONE target_orig; MERGE INTO target USING (select k, max(v) as v from src group by k) AS b ON target.k = b.k WHEN MATCHED THEN UPDATE SET target.v = b.v WHEN NOT MATCHED THEN INSERT (k, v) VALUES (b.k, b.v);
No exemplo a seguir, a tabela members armazena os nomes, endereços e taxas atuais (members.fee) pagas a uma academia local. A tabela signup armazena a data de matrícula de cada membro (signup.date). A instrução MERGE aplica uma taxa padrão de $40 aos membros que ingressaram na academia há mais de 30 dias, depois que o período de experiência gratuita expirou:
MERGE INTO members m USING ( SELECT id, date FROM signup WHERE DATEDIFF(day, CURRENT_DATE(), signup.date::DATE) < -30) s ON m.id = s.id WHEN MATCHED THEN UPDATE SET m.fee = 40;