Supongamos que tiene las tablas Presentations
y Events
. Cuando se guarda una presentación y contiene información básica del evento, como la ubicación y la fecha, se creará un evento automáticamente con un desencadenador. (Me temo que es imposible por razones técnicas simplemente mantener los datos en un solo lugar y usar una vista.) Además, al cambiar esta información más adelante en la presentación, el desencadenador copiará las actualizaciones al evento también, de este modo:¿Evita la ejecución mutuamente recursiva de desencadenantes?
CREATE TRIGGER update_presentations
ON Presentations
AFTER UPDATE
AS
BEGIN
UPDATE Events
SET Events.Date = Presentations.Date,
Events.Location = Presentations.Location
FROM Presentations INNER JOIN Events ON Presentations.EventID = Events.ID
WHERE Presentations.ID IN (SELECT ID FROM inserted)
END
Ahora, el cliente lo desea de manera que, si un usuario cambia nunca la información en el caso , debe volver a la presentación también. Por razones obvias, no puedo hacer lo contrario:
CREATE TRIGGER update_events
ON Events
AFTER UPDATE
AS
BEGIN
UPDATE Presentations
SET Presentations.Date = Events.Date,
Presentations.Location = Events.Location
FROM Events INNER JOIN Presentations ON Events.PresentationID = Presentations.ID
WHERE Events.ID IN (SELECT ID FROM inserted)
END
Después de todo, esto provocaría que cada disparador se disparara entre sí. Lo que podría hacer es agregar una columna last_edit_by
a ambas tablas, que contiene una identificación de usuario. Si llenados por el gatillo con un ID válido especial (por ejemplo, haciendo que todos los ID de usuario de las personas reales positivos, pero identificaciones de usuario de los guiones negativos), que podrían usar eso como una condición de salida:
AND last_edit_by >= 0
Esto podría funcionar , pero lo que me gustaría hacer es indicarle al servidor SQL que, dentro de una transacción, un disparador solo debería disparar una vez. ¿Hay alguna manera de verificar esto? ¿O tal vez para verificar que una tabla ya haya sido afectada por un disparador?
respuesta gracias a Steve Robbins:
Simplemente envuelva los potencialmente anidados UPDATE
declaraciones en una condición IF comprobación de trigger_nestlevel()
. Por ejemplo:
CREATE TRIGGER update_presentations
ON Presentations
AFTER UPDATE
AS
BEGIN
IF trigger_nestlevel() < 2
UPDATE Events
SET Events.Date = Presentations.Date,
Events.Location = Presentations.Location
FROM Presentations INNER JOIN Events ON Presentations.EventID = Events.ID
WHERE Presentations.ID IN (SELECT ID FROM inserted)
END
Tenga en cuenta que trigger_nestlevel()
parece estar basada en 1, no basado en 0. Si desea que cada uno de los dos desencadenantes se ejecute una vez, pero no con mayor frecuencia, simplemente marque trigger_nestlevel() < 3
en ambos disparadores.
disparadores anidados en realidad están deshabilitados en esa base de datos. Mi problema es el caso del disparador A que dispara B que dispara A, no A que dispara A directamente. La configuración no impide esto. –
Eso es desencadenante recursivo, no estoy en una máquina en este momento pero estoy seguro de que también hay desencadenadores anidados que puede configurar con sp_config. Han pasado algunos años desde que enfrenté este problema. –
Tienes razón; disparadores anidados es otra opción. Pero por la forma en que leo su documentación, evitaría que B disparara después de A, mientras que yo quiero evitar que A dispare por segunda vez. –