Skip to content

Использование триггера INSTEAD OF для обновления представления

Пересказ статьи Chad Callihan. Using INSTEAD OF Trigger to Update View


Недавно я столкнулся со странной проблемой, и мне подумалось, что это может стать отличным постом в блоге. Мне сообщили о стандартном процессе в приложении, который завершался неудачно со следующей ошибкой SQL:


Msg 4405, Level 16, State 1, Line 19
View or function ‘XXXXX’ is not updatable because the modification affects multiple base tables.

(Представление или функция не является обновляемым, поскольку модификация затрагивает несколько базовых таблиц.)


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

Давайте рассмотрим небольшой пример, использующий триггер INSTEAD OF для обновления представления.

Добро или зло


Сначала мы создадим пару таблиц с именами героя и злодея:

CREATE TABLE Hero (
Id INT PRIMARY KEY
,H_Name VARCHAR(20) NOT NULL
);
CREATE TABLE Villain (
Id INT PRIMARY KEY
,V_Name VARCHAR(20) NOT NULL
);

Давайте начнем с этой знаменитой пары:

INSERT Hero VALUES (1,'Batman');
INSERT Villain VALUES( 1,'Joker');

И добавим представление, чтобы видеть их вместе:

CREATE VIEW Rivals
AS
SELECT h.*
,v.V_Name
FROM Hero h
JOIN Villain v ON h.id = v.id;



Что если мы захотим, чтобы нашей первой парой были Superman и Lex Luthor, а не Batman и Joker? Если мы попытаемся выполнить оператор обновления, то получим ошибку:

UPDATE Rivals
SET H_Name = 'Superman'
,V_Name = 'Lex Luthor'
WHERE Id = 1;
GO



Msg 4405, Level 16, State 1, Line 19
View or function ‘Rivals’ is not updatable because the modification affects multiple base tables.
(Представление или функция ‘Rivals’ не является обновляемым, поскольку модификация влияет на несколько базовых таблиц.)



Человек из стали


Как нам обойти эту ошибку? Одним из решений является добавление триггера INSTEAD OF UPDATE. Мы будем использовать этот триггер для замены героя и злодея новыми героем и злодеем:

CREATE TRIGGER InsteadRivals ON Rivals
INSTEAD OF UPDATE
AS
BEGIN
UPDATE h
SET h.H_Name = i.H_Name
FROM INSERTED i
JOIN Hero h ON i.Id = h.Id
PRINT 'Updated Hero Table'
UPDATE v
SET v.V_Name = i.V_Name
FROM INSERTED i
JOIN Villain v ON i.Id = v.Id
PRINT 'Updated Villain Table'
END
GO

Теперь мы снова можем выполнить наше обновление и увидеть, что изменения произошли:

UPDATE Rivals
SET H_Name = 'Superman'
,V_Name = 'Lex Luthor'
WHERE Id = 1;
GO



Наше обновление теперь прошло успешно, и мы можем видеть наших новых соперников:

SELECT * FROM Rivals;
GO


Категории: T-SQL

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Нет комментариев.

Автор не разрешил комментировать эту запись

Добавить комментарий

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Добавленные комментарии должны будут пройти модерацию прежде, чем будут показаны.