Подтвердить что ты не робот

Предотвратить взаимно-рекурсивное выполнение триггеров?

Предположим, что у вас есть таблицы Presentations и Events. Когда презентация сохраняется и содержит основную информацию о событии, такую ​​как местоположение и дата, событие будет создано автоматически с помощью триггера. (Я боюсь, что по техническим причинам невозможно просто сохранить данные в одном месте и использовать представление.) Кроме того, при изменении этой информации позже в презентации триггер также скопирует обновления на событие, так:

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

Теперь клиент хочет его, чтобы, если пользователь когда-либо меняет информацию в событии, он также должен вернуться к презентации. По очевидным причинам я не могу сделать обратное:

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

В конце концов, это приведет к срабатыванию каждого триггера друг за другом. Я мог бы добавить столбец last_edit_by в обе таблицы, содержащие идентификатор пользователя. Если он заполнен триггером со специальным недопустимым идентификатором (скажем, сделав все идентификаторы пользователей действительных лиц положительными, а идентификаторы пользователей сценариев отрицательными), я мог бы использовать это как условие выхода:

    AND last_edit_by >= 0

Это может сработать, но то, что я хотел бы сделать, это указать серверу SQL, что в транзакции триггер должен запускать только один раз. Есть ли способ проверить это? Или, возможно, проверить, что на стол уже повлиял триггер?


Отвечайте благодаря Стиву Роббинсу:

Просто оберните потенциально вложенные операторы UPDATE в состоянии IF, проверяя trigger_nestlevel(). Например:

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

Обратите внимание, что trigger_nestlevel() похоже на 1, а не на 0. Если вы хотите, чтобы каждый из двух триггеров выполнялся один раз, но не чаще, просто проверьте trigger_nestlevel() < 3 в обоих триггерах.

4b9b3361

Ответ 1

Я не уверен, что вы делаете это за транзакцию, но вам нужны вложенные триггеры для других частей? Если вы отключите их на сервере, то триггер не будет запускаться из другого триггера, обновляющего таблицу.

EDIT (ответ из комментариев): Вам нужно будет изменить триггер A, чтобы использовать TRIGGER_NESTLEVEL