Estoy tratando de implementar su funcionalidad UPSERT básica, pero con un giro: a veces no quiero actualizar realmente una fila existente.¿Cómo implementar un procedimiento almacenado condicional Upsert?
Básicamente, estoy tratando de sincronizar algunos datos entre repositorios diferentes, y una función Upsert me pareció el camino a seguir. Basándome en gran medida en Sam Saffron's answer to this question, así como en otras investigaciones y lecturas, se me ocurrió este procedimiento almacenado:
(nota: estoy usando MS SQL Server 2005, entonces la instrucción MERGE no es una opción)
CREATE PROCEDURE [dbo].[usp_UpsertItem]
-- Add the parameters for the stored procedure here
@pContentID varchar(30) = null,
@pTitle varchar(255) = null,
@pTeaser varchar(255) = null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRANSACTION
UPDATE dbo.Item WITH (SERIALIZABLE)
SET Title = @pTitle,
Teaser = @pTeaser
WHERE ContentID = @pContentID
IF @@rowcount = 0
INSERT INTO dbo.Item (ContentID, Title, Teaser)
VALUES (@pContentID, @pTitle, @pTeaser)
COMMIT TRANSACTION
END
Me siento cómodo con esto para un Upsert básico, pero me gustaría hacer la actualización real condicional en el valor de otra columna. Piense en ello como "bloquear" una fila para que el procedimiento Upsert no pueda realizar más actualizaciones. Podría cambiar la instrucción UPDATE, así:
UPDATE dbo.Item WITH (SERIALIZABLE)
SET Title = @pTitle,
Teaser = @pTeaser
WHERE ContentID = @pContentID
AND RowLocked = false
Pero entonces la inserción posterior fallaría con una violación de restricción única (para el campo Content ID) cuando se intenta insertar una fila que ya existe pero no se actualiza porque Estaba bloqueado".
¿Significa esto que ya no tengo un Upsert clásico, es decir, que tendré que seleccionar la fila cada vez para determinar si se puede actualizar o insertar? Apuesto a que ese es el caso, así que supongo que lo que realmente estoy pidiendo es ayudar a que el nivel de aislamiento de la transacción sea correcto para que el procedimiento se ejecute de manera segura.
¿Qué es RowLocked in (AND RowLocked = false)? ¿Es una columna en tu mesa? –
@AlexKuznetsov - Sí, se supone que RowLocked es una columna de tabla; en realidad, hay un par de columnas que dictan si una fila debe estar "bloqueada" (es decir, no actualizada mediante este procedimiento), pero simplifiqué mi SQL para tratar de aclarar mi pregunta; aunque tiene un poco de descuido con la sintaxis, debería, por supuesto, ser "AND RowLocked = 0" y debería haber mencionado que es un poco de columna. – Matt