Предположим, у вас есть таблицы 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
в обоих триггерах.