A operação UPSERT atualiza ou insere uma linha em uma tabela, dependendo se a tabela já tiver uma linha que corresponda aos dados:
if table t has a row exists that has key X:
update t set mystuff... where mykey=X
else
insert into t mystuff...
Como a Oracle não possui uma declaração UPSERT específica, qual é a melhor maneira de fazer isso?
A instrução MERGE mescla dados entre duas tabelas. O uso do DUAL nos permite usar este comando. Observe que isso não está protegido contra acesso simultâneo.
fonte
O exemplo duplo acima, que está em PL / SQL, foi ótimo porque eu queria fazer algo semelhante, mas queria do lado do cliente ... então, aqui está o SQL que usei para enviar uma declaração semelhante diretamente de algum c #
No entanto, da perspectiva do C #, isso deve ser mais lento do que fazer a atualização e ver se as linhas afetadas eram 0 e fazer a inserção, se fosse.
fonte
MERGE
, e eu prefiro usar muito mais simplesDELETE
entãoINSERT
.MERGE INTO mytable d USING (SELECT 1 id, 'x' name from dual) s ON (d.id = s.id) WHEN MATCHED THEN UPDATE SET d.name = s.name WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name);
Outra alternativa sem a verificação de exceção:
fonte
fonte
Nenhuma das respostas dadas até agora é segura diante de acessos simultâneos , como apontado no comentário de Tim Sylvester, e criará exceções em caso de corridas. Para corrigir isso, a combinação de inserção / atualização deve ser agrupada em algum tipo de instrução de loop, para que, em caso de exceção, a coisa toda seja repetida.
Como exemplo, veja como o código do Grommit pode ser agrupado em um loop para torná-lo seguro quando executado simultaneamente:
NB No modo de transação
SERIALIZABLE
, que eu não recomendo, você pode encontrar o ORA-08177: não pode serializar o acesso a essas exceções de transação .fonte
Eu gostaria da resposta do Grommit, exceto que isso exige valores duvidosos. Encontrei a solução em que ela pode aparecer uma vez: http://forums.devshed.com/showpost.php?p=1182653&postcount=2
fonte
INSERT (B.CILT, B.SAYFA, B.KUTUK, B.MERNIS_NO) VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO);
?Uma observação sobre as duas soluções que sugerem:
1) Insira, se a exceção for atualizada,
ou
2) Atualize, se sql% rowcount = 0, insira
A questão de inserir ou atualizar primeiro também depende do aplicativo. Você espera mais inserções ou mais atualizações? Aquele com maior probabilidade de sucesso deve ir primeiro.
Se você escolher o errado, receberá várias leituras de índice desnecessárias. Não é um grande negócio, mas ainda há algo a considerar.
fonte
Eu tenho usado o primeiro exemplo de código há anos. Observe não encontrado e não conte.
O código abaixo é o código possivelmente novo e aprimorado
No primeiro exemplo, a atualização faz uma pesquisa de índice. É necessário, para atualizar a linha direita. O Oracle abre um cursor implícito e o usamos para quebrar uma inserção correspondente, para que saibamos que a inserção acontecerá apenas quando a chave não existir. Mas a inserção é um comando independente e precisa fazer uma segunda pesquisa. Não conheço o funcionamento interno do comando mesclar, mas como o comando é uma única unidade, o Oracle pode executar a inserção ou atualização correta com uma única pesquisa de índice.
Acho que a mesclagem é melhor quando você tem algum processamento a ser feito, o que significa pegar dados de algumas tabelas e atualizar uma tabela, possivelmente inserindo ou excluindo linhas. Mas para o caso de linha única, você pode considerar o primeiro caso, já que a sintaxe é mais comum.
fonte
Copie e cole um exemplo para alterar uma tabela para outra, com MERGE:
Resultado:
fonte
Tente isso,
fonte
Em http://www.praetoriate.com/oracle_tips_upserts.htm :
"No Oracle9i, um UPSERT pode realizar esta tarefa em uma única declaração:"
fonte