Mucha gente te sugerirá que uses MERGE
, pero te advierto que no lo hagas. De forma predeterminada, no lo protege de las condiciones de concurrencia y de carrera más que varias declaraciones, pero presenta otros peligros:
- Tenga cuidado con la instrucción MERGE de SQL Server
- Qué evitar si desea utilizar MERGE
- Patrones UPSERT y Antipatrones de SQL Server
Incluso con esta sintaxis "más simple" disponible, sigo prefiriendo este enfoque (se omite el manejo de errores por brevedad):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;
Más información sobre este UPSERT
enfoque aquí:
- Deje de usar este antipatrón UPSERT
Mucha gente lo sugerirá de esta manera:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
UPDATE ...
END
ELSE
BEGIN
INSERT ...
END
COMMIT TRANSACTION;
Pero todo lo que esto logra es garantizar que es posible que deba leer la tabla dos veces para ubicar las filas que se actualizarán. En la primera muestra, solo necesitará ubicar las filas una vez. (En ambos casos, si no se encuentran filas de la lectura inicial, se produce una inserción).
Otros sugerirán de esta manera:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
Sin embargo, esto es problemático aunque solo sea por la razón de que permitir que SQL Server detecte excepciones que podría haber evitado en primer lugar es mucho más costoso, excepto en el caso poco frecuente en el que casi todas las inserciones fallan. Lo demuestro mucho aquí:
- Comprobación de posibles violaciones de restricciones antes de ingresar TRY/CATCH
- Impacto en el rendimiento de diferentes técnicas de manejo de errores
No estoy seguro de lo que cree que gana al tener una sola declaración; No creo que ganes nada. MERGE
es una declaración única, pero aún tiene que realizar múltiples operaciones de todos modos, aunque te hace pensar que no lo hace.