Триггер, чтобы остановить определенное поле, установленное в NULL (одиночные и многострочные обновления)
Можно ли создать триггер, который будет проверять, задано ли для определенного поля значение NULL (из однострочного или многострочного обновления), и, если это так, вернуть это поле к его первоначальному значению?
Я искал на сайте, но не нашел ничего, что соответствует моим точным требованиям.
Немного предыстории:
У нас есть два приложения (веб-приложение управления временем и сервер проектов Microsoft), которые отправляют друг другу обновления о ресурсах в нашей организации. Когда в одну из систем вносятся изменения, она отправляет это обновление другой системе. Однако существуют определенные поля, которые существуют только в веб-приложении управления временем (имя таблицы resource
), и сервер MSP форсирует одно из этих полей (имя поля GLMaskingValue
) чтобы NULL
с некоторыми из его обновлений (не все, насколько я могу судить).
У меня нет доступа к коду, только база данных веб-приложения, и я не хочу, чтобы весь оператор обновления не выполнялся (что, как я понял, я мог бы сделать, используя ограничения таблиц) - я просто хочу вернуть это поле назад, когда и если кто-то пытается изменить его на NULL
,
Я иду по пути триггеров, но вполне может быть гораздо лучший способ сделать это - если так, пожалуйста, просветите меня!
3 ответа
Что-то вроде этого:
CREATE TRIGGER trig_test
ON dbo.t
AFTER update
AS
update t
set t.x = d.x
from t as t
join deleted d
on t.id = d.id -- use the primary key of the table instead of id
where t.x is null
Если проблема связана только с обновлениями, да, вы можете применить это с помощью триггера "вместо обновления", предостережение заключается в том, что вы должны написать инструкцию обновления, чтобы применить изменения:
create table data (id int not null, name varchar(50), postcode varchar(50), sex bit, primary key(id))
go
create trigger tg_data_before on data instead of update as
begin
set nocount on
update data
set name = coalesce(c.name, b.name),
postcode = coalesce(c.postcode, b.postcode),
sex = coalesce(c.sex, b.sex)
from data a
join deleted b on a.id = b.id
join inserted c on a.id = c.id
end
go
insert data values (1, 'sven', '1234', 0)
insert data values (2, 'lars', '2345', 0)
insert data values (3, 'foo', '3456', 1)
update data set name = null
update data set postcode = null where id = 1
update data set postcode = 'zoink' where id in (2,3)
update data set sex = 1-sex
select * from data
drop table data
Но я думаю, что было бы лучше просто использовать "not null" и исправить клиентский код, который явно делает неправильные вещи (явно обнуляет поле, которое не должно быть null, или делает неохраняемую вставку / слияния):
create table data (id int not null, name varchar(50) not null, postcode varchar(50) not null, sex bit not null, primary key(id))
Похоже, хороший план, пока код не может быть исправлен. Вот многострочный, многостолбцовый триггер. Преимущество заключается в том, что обновление будет выполняться только в том случае, если один или оба столбца изменились. Также обратите внимание, что он действует только на строки / столбцы, где предыдущие значения не были нулевыми.
CREATE TRIGGER tr_resource_nullcheck ON resource
FOR UPDATE
AS
SET NOCOUNT ON
IF (UPDATE(GLMaskingValue) OR UPDATE(Column2))
BEGIN
update r
set r.GLMaskingValue = isnull(r.GLMaskingValue, d.GLMaskingValue)
r.column2 = isnull(r.column2, d.column2)
from resource r
join deleted d on d.resourceId = r.resourceId
where (r.GLMaskingValue is null and d.GLMaskingValue is not null)
or (r.column2 is null and d.column2 is not null)
END