我有table Addresses
列ID (PK), EmpID (int), Address (nvarchar(100), IsDefault (bit)
。
现在我必须确保只有一个具有相同EmpID的记录将IsDefault设置为1。
我现在已经完成了触发器的操作。
第一个是插入触发器。首先,检查IsDefault
中是否输入了值1。如果是,那么它检查是否有多个记录在1上设置了相同的EmpID
和IsDefault
值。如果这也是真的,则它为所有其他IsDefault
值设置相同EmpID
到0.:
create trigger [dbo].[TRG_dbo_Addresses_IsDefault_OnlyOneRecord_insert]
on [dbo].[lAddressesOrganisations]
after insert
as
begin
set nocount on;
begin try
if exists (
select *
from inserted as i
where i.IsDefault = 1)
begin
if (
select count(*)
from dbo.Addresses as lao
inner join inserted as i on i.ID=lao.ID
where lao.IsDefault = 1
and lao.EmpID = i.EmpID
) > 1
begin
update lao
set lao.IsDefault = 0
from dbo.Addresses as lao
where (
select row_number () over (partition by EmpID order by ID desc) as rn
from dbo.Addresses as lao
) > 1
end
end
end try
begin catch
if @@trancount > 0
rollback tran;
end catch
end
另一个是更新触发器,我不知道如何编写它。首先它与插入触发器相同,检查插入的值是1,其中值为0.如果是,如果有多个记录,同一EmpID
和IsDefault
设置为1.如果是,
如何写入所有其他记录对于同一EmpID
设置为0,而正在更新的记录是否仍为1?
create trigger [dbo].[TRG_dbo_Addresses_IsDefault_OnlyOneRecord_update]
on [dbo].[Addresses]
after update
as
begin
set nocount on;
begin try
if exists (
select *
from inserted as i
inner join deleted as d on d.ID=i.ID
where i.IsDefault = 1
and d.IsDefault = 0)
begin
if (
select count(*)
from dbo.Addresses as lao
inner join inserted as i on i.ID=lao.ID
where lao.IsDefault = 1
and lao.EmpID = i.EmpID
) > 1
begin
update lao
set lao.IsDefault = 0
from dbo.Addresses as lao
inner join inserted as i on i.ID=lao.ID
where (I don't have an idea what to put here)
and lao.OrganisationID = i.OrganisationID
end
end
end try
begin catch
if @@trancount > 0
rollback tran;
end catch
end
我正在使用ms sql 2016。
答案 0 :(得分:1)
我同意马特:如果可能,请避免触发。
无论如何,我认为在你的UPDATE触发器中你应该改为:
if (
select count(*)
from dbo.Addresses as lao
inner join inserted as i on lao.EmpID = i.EmpID
where lao.IsDefault = 1
) > 1
begin
update lao
set lao.IsDefault = 0
from dbo.Addresses as lao
inner join inserted as i on lao.EmpID = i.EmpID
where lao.IsDefault = 1
and lao.ID <> i.id
end
Morevore,您可以将其重写为:
IF EXISTS(SELECT 1 FROM
FROM dbo.Addresses as lao
INNER join inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1 AND lao.ID <>i.ID)
BEGIN
UPDATE lao
SET lao.IsDefault = 0
FROM dbo.Addresses as lao
INNER JOIN inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
and lao.ID <> i.id
END
您也应该更改插入触发器。
更新:插入触发器。 到目前为止,我可以看到(但我不能做测试,所以请完成案例测试),如果ID总是最大值,或者如果你想保留插入的最后一个id的默认值,我认为你可以重写你的插入触发器以下:(你也可以删除IF,如果你不关心总是为零行做一个UPDATE)
as
begin
set nocount on;
begin try
IF EXISTS(SELECT 1
FROM dbo.Addresses as lao
INNER join inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
AND lao.ID <>i.ID
AND i.IsDefault=1)
BEGIN
UPDATE lao
SET lao.IsDefault = 0
FROM dbo.Addresses as lao
INNER JOIN inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
and lao.ID <> i.id
AND i.IsDefault=1
END
end try
begin catch
if @@trancount > 0
rollback tran;
end catch
此更改(AND i.IsDefault = 1)也可以应用于UPDATE触发器。
答案 1 :(得分:0)
我可能会考虑您在这里尝试解决的问题是否可以在没有触发器的情况下解决。触发器往往会带来显着的性能损失,并且可以将逻辑与代码的其余部分分开,这使得将来维护成为一个令人头痛的问题。
如果你真的想在行插入/更新上使用触发器解决方案,并且总是只有1行标记了该位,请不要尝试用它来计算行数。只需将相关EmpID的所有行设置为0,然后在触发器中将插入的行更新为1.