He escrito un proceso almacenado que hará una actualización si existe un registro, de lo contrario, hará una inserción. Se parece a esto:
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
Mi lógica detrás de escribirlo de esta manera es que la actualización realizará una selección implícita usando la cláusula where y si eso devuelve 0, entonces se llevará a cabo la inserción.
La alternativa a hacerlo de esta manera sería hacer una selección y luego, según el número de filas devueltas, hacer una actualización o una inserción. Esto lo consideré ineficiente porque si va a hacer una actualización, causará 2 selecciones (la primera llamada de selección explícita y la segunda implícita en el dónde de la actualización). Si el proceso hiciera un inserto, no habría diferencia en la eficiencia.
¿Mi lógica suena aquí? ¿Es así como combinaría una inserción y una actualización en un proceso almacenado?
Lea la publicación en mi blog para obtener un patrón bueno y seguro que pueda usar. Hay muchas consideraciones y la respuesta aceptada a esta pregunta está lejos de ser segura.
Para una respuesta rápida, pruebe el siguiente patrón. Funcionará bien en SQL 2000 y superior. SQL 2005 le brinda manejo de errores que abre otras opciones y SQL 2008 le brinda un comando MERGE.
fuente
Si se va a utilizar con SQL Server 2000/2005, el código original debe incluirse en la transacción para asegurarse de que los datos permanezcan consistentes en un escenario concurrente.
Esto supondrá un coste de rendimiento adicional, pero garantizará la integridad de los datos.
Agregue, como ya se sugirió, MERGE debe usarse donde esté disponible.
fuente
MERGE es una de las nuevas características de SQL Server 2008, por cierto.
fuente
No solo necesita ejecutarlo en una transacción, también necesita un alto nivel de aislamiento. De hecho, el nivel de aislamiento predeterminado es Lectura confirmada y este código necesita serializable.
Tal vez agregar también la verificación de error @@ y la reversión podría ser una buena idea.
fuente
Si no está haciendo una fusión en SQL 2008, debe cambiarlo a:
si @@ rowcount = 0 y @@ error = 0
de lo contrario, si la actualización falla por alguna razón, lo intentará y luego lo insertará porque el recuento de filas en una declaración fallida es 0
fuente
Gran fan de UPSERT, realmente reduce el código para administrar. Aquí hay otra forma en que lo hago: uno de los parámetros de entrada es ID, si el ID es NULL o 0, sabes que es un INSERT, de lo contrario es una actualización. Asume que la aplicación sabe si hay una identificación, por lo que no funcionará en todas las situaciones, pero reducirá las ejecuciones a la mitad si lo hace.
fuente
Publicación de Dima Malenko modificada:
Puede capturar el error y enviar el registro a una tabla de inserción fallida.
Necesitaba hacer esto porque tomamos los datos que se envían a través de WSDL y, si es posible, los arreglamos internamente.
fuente
Su lógica parece sólida, pero es posible que desee considerar agregar algún código para evitar la inserción si ha pasado una clave primaria específica.
De lo contrario, si siempre está haciendo una inserción si la actualización no afectó ningún registro, ¿qué sucede cuando alguien elimina el registro antes de que se ejecute "UPSERT"? Ahora, el registro que estaba intentando actualizar no existe, por lo que creará un registro en su lugar. Probablemente ese no sea el comportamiento que estabas buscando.
fuente