Eu escrevi um procedimento armazenado que fará uma atualização se houver um registro, caso contrário, fará uma inserção. É mais ou menos assim:
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
Minha lógica por trás de escrever desta forma é que a atualização executará uma seleção implícita usando a cláusula where e se retornar 0, então a inserção ocorrerá.
A alternativa para fazer dessa maneira seria fazer uma seleção e, a seguir, com base no número de linhas retornadas, fazer uma atualização ou uma inserção. Isso eu considerei ineficiente porque se você for fazer uma atualização causará 2 selects (a primeira chamada select explícita e a segunda implícita no where da atualização). Se o proc fizesse uma inserção, não haveria diferença na eficiência.
Minha lógica está soando aqui? É assim que você combinaria uma inserção e uma atualização em um procedimento armazenado?
Leia a postagem em meu blog para ver um padrão bom e seguro que você pode usar. Há muitas considerações e a resposta aceita para essa pergunta está longe de ser segura.
Para uma resposta rápida, tente o seguinte padrão. Funcionará bem no SQL 2000 e superior. O SQL 2005 fornece tratamento de erros que abre outras opções e o SQL 2008 fornece um comando MERGE.
fonte
Se for usado com o SQL Server 2000/2005, o código original precisa ser incluído na transação para garantir que os dados permaneçam consistentes no cenário simultâneo.
Isso incorrerá em custos de desempenho adicionais, mas garantirá a integridade dos dados.
Adicione, como já sugerido, MERGE deve ser usado quando disponível.
fonte
MERGE é um dos novos recursos do SQL Server 2008, aliás.
fonte
Você não precisa apenas executá-lo na transação, mas também precisa de um alto nível de isolamento. Na verdade, o nível de isolamento padrão é Read Commited e esse código precisa Serializable.
Talvez adicionar também a verificação de erro @@ e reversão possa ser uma boa ideia.
fonte
Se você não estiver fazendo uma mesclagem no SQL 2008, deve alterá-lo para:
se @@ rowcount = 0 e @@ error = 0
caso contrário, se a atualização falhar por algum motivo, ele tentará inserir depois porque o número de linhas em uma instrução com falha é 0
fonte
Grande fã do UPSERT, realmente reduz o código para gerenciar. Aqui está outra maneira de fazer isso: Um dos parâmetros de entrada é o ID, se o ID for NULL ou 0, você sabe que é um INSERT, caso contrário, é uma atualização. Presume que o aplicativo sabe se há um ID, então não funcionará em todas as situações, mas reduzirá a execução pela metade se você o fizer.
fonte
Postagem modificada de Dima Malenko:
Você pode interceptar o erro e enviar o registro para uma tabela de inserção com falha.
Eu precisava fazer isso porque estamos pegando todos os dados enviados via WSDL e, se possível, corrigindo-os internamente.
fonte
Sua lógica parece correta, mas você pode querer considerar a adição de algum código para evitar a inserção se você tiver passado uma chave primária específica.
Caso contrário, se você está sempre fazendo uma inserção se a atualização não afetou nenhum registro, o que acontece quando alguém exclui o registro antes de executar o "UPSERT"? Agora, o registro que você estava tentando atualizar não existe, então, em vez disso, será criado um registro. Esse provavelmente não é o comportamento que você estava procurando.
fonte