2009-01-10 26 views
17

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.

Respuesta

18

No estoy seguro de hacerlo por transacción, pero ¿necesita activadores anidados activados para otras partes? Si los apaga en el servidor, no se activará un disparador desde otro activador al actualizar una tabla.

EDITAR (respuesta de los comentarios): Usted necesitará alterar Un gatillo para usar TRIGGER_NESTLEVEL

+0

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. –

+0

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. –

+0

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. –

Cuestiones relacionadas