Múltiples sentencias de ACTUALIZACIÓN de SQL ¿O solo con CASE?
-
08-07-2019 - |
Pregunta
He creado un desencadenador donde intento mantener las prioridades en orden y no permitir valores de prioridad duplicados. Hay algunas cosas a considerar.
- El usuario puede liberar la forma en la prioridad.
- No hay nada que les impida elegir la misma prioridad que otro elemento.
-
Cuando se ingresa un valor igual a otro valor, el elemento recientemente priorizado debe tener prioridad en la prioridad y el otro debe incrementarse.
CREATE TRIGGER dbo.trg_Priority ON dbo.Stories AFTER INSERT,UPDATE,DELETE AS BEGIN SET NOCOUNT ON; -- Insert statements for trigger here DECLARE @StoryId INT DECLARE @OldLocation INT DECLARE @NewLocation INT SELECT @NewLocation = Priority, @StoryId = StoryId FROM INSERTED SELECT @OldLocation = Priority FROM DELETED IF @NewLocation = @OldLocation RETURN; IF @NewLocation IS NULL BEGIN UPDATE Stories SET Priority = Priority - 1 WHERE Priority > @OldLocation END IF @NewLocation > @OldLocation BEGIN UPDATE Stories SET Priority = Priority + 1 WHERE Priority >= @NewLocation AND StoryId <> @StoryId END IF @NewLocation < @OldLocation BEGIN UPDATE Stories SET Priority = Priority + 1 WHERE Priority >= @NewLocation AND Priority < @OldLocation AND StoryId <> @StoryId END END GO
No he probado mucho este disparador, así que si hay áreas de preocupación, no dude en hablar. Lo que finalmente quiero saber es si debería intentar convertir esto en una única actualización con una declaración de caso. (Si eso es posible).
¡Si fuera más eficiente hacer esto una sola declaración UPDATE
, realmente podría usar una mano para resolverlo!
Solución
Necesita reescribir el disparador. Se supone que solo se insertará / actualizará o eliminará un solo registro a la vez. No puede escribir un activador con esa suposición, los activadores operan en lotes de datos, no en filas. Debe unirse a insertado y eliminado en sus actualizaciones. Entonces sí, trataría de escribir la actualización con una declaración de caso.
¿Y por qué es esto un disparador eliminado? No habrá un registro para actualizar si se eliminó.
Otros consejos
Asegúrese de retroceder y generar un error (gravedad 16) si @@ ROWCOUNT > 1. Su activador como está escrito actualmente causaría una gran cantidad de corrupción de datos del usuario que intentó insertar, actualizar o eliminar varias filas a la vez.
Dicho esto, IronGoofy tiene razón: solo tocarás la mesa una vez, independientemente de la condición. Entonces, dividirlo en varias declaraciones hace que el código sea más fácil de leer / más fácil de mantener.
Si permitiera que se actualizaran varias filas a la vez, necesitaría cambiar esto. ¡La lógica puede ser desalentadora!
¿Qué tal esto?
UPDATE Stories SET Priority = CASE
WHEN Priority > @OldLocation THEN Priority-1
WHEN Priority >= @NewLocation AND StoryID <> @StoryID THEN Priority+1
WHEN Priority >= @NewLocation AND @Priority < @OldLocation And StoryID <> StoryID THEN Priority +1
END
GO
No debería haber ninguna diferencia (notable) de rendimiento, en cualquier caso, emitirá una única declaración de actualización a la base de datos.
Decidí deshacerme de esta idea y lo dejo a la interfaz de usuario para actualizar la prioridad. He dejado de permitir la entrada del usuario.
No estoy seguro de cuáles de estas respuestas son correctas, así que voy a marcar esto como correcto y dejar que la comunidad lo resuelva con prueba y error. :)