我已经在一个表上实现了一个触发器,以确保该表不包含多于一行的数据,其中一列的位值为1。但是触发器以某种方式不能正常工作。
create trigger [dbo].[flyingdutchman_needs_a_captain]
on [dbo].[flyingdutchman]
after insert, update, delete as
begin
set nocount on;
set rowcount 0;
begin try
declare @captainsum int
set @captainsum = 0
set @captainsum = (select sum(case when uniontable.iscaptain = 1 then 1 else 0 end)
from (
select iscaptain from dbo.flyingdutchman
union all
select inserted.iscaptain as iscaptain from inserted
union all
select deleted.iscaptain as iscaptain from deleted
) as uniontable
having sum(case when uniontable.iscaptain = 1 then 1 else 0 end) <> 1)
if(@captainsum <> 1)
begin
throw 50000,'flying dutchman is cursed and needs a captain.',1;
end
end try
begin catch
if xact_state()<>0
rollback transaction;
throw;
end catch
end
flyingdutchman是一个包含三列的表格:
SailorId(int),SailorName(varchar),IsCaptain(bit)
以及以下各行:
执行查询时:
insert into dbo.flyingdutchman(Sailorname,IsCaptain)
values('Davy Jones',1)
我得到了错误:
消息50000,级别16,状态1,过程 FLYINGDUTCHMAN_NEEDS_A_CAPTAIN,第XX行FULLING DUTCHMAN被诅咒, 需要一个船长。
我希望此查询运行正常,并且不会触发触发器。
答案 0 :(得分:2)
由于这是一个after
触发器,因此所有更改已在表中-您无需查询inserted
和deleted
表-这就是您获得错误的结果。
您可以简单地执行以下操作:
if 1 <> (select count(*) from dbo.flyingdutchman where iscaptain = 1)
throw 50000,'flying dutchman is cursed and needs a captain.',1;
但是,我怀疑您可能应该这样做:
declare @captainsCount int;
select @captainsCount = count(*) from dbo.flyingdutchman where iscaptain = 1
if @captainsCount = 0
throw 50000,'flying dutchman is cursed and needs a captain.',1;
if @captainsCount > 1
throw 50000,'flying dutchman has too many captains.',1;
答案 1 :(得分:2)
可以简化为:
create trigger [dbo].[flyingdutchman_needs_a_captain]
on [dbo].[flyingdutchman]
after insert, update, delete as
begin
set nocount on;
begin try
-- prevents multiple captains
IF (SELECT COUNT(*) FROM [dbo].[flyingdutchman] WHERE iscaptain = 1 ) > 1
throw 50000,'Too many captains is not good.',1;
-- prevents setting all captains off, if one was already assigned
IF NOT EXISTS(SELECT * FROM [dbo].[flyingdutchman] WHERE iscaptain = 1 )
AND EXISTS(SELECT * FROM deleted WHERE iscaptain = 1 )
throw 50001,'flying dutchman is cursed and needs a captain.',1;
end try
begin catch
if xact_state()<>0
rollback transaction;
throw;
end catch
end
答案 2 :(得分:2)
您的触发器始终会触发,因为您的条件if(@captainsum <> 1)
始终为真
当子查询中的摘要等于1时,@captainsum
= null(由于您具有hading语句),则您的变量为null或除1以外的其他值
create trigger [dbo].[flyingdutchman_needs_a_captain]
on [dbo].[flyingdutchman]
after insert, update, delete as
begin
set nocount on;
set rowcount 0;
begin try
declare @captainsum int
set @captainsum = 0
set @captainsum = (select sum(case when uniontable.iscaptain = 1 then 1 else 0 end)
from (
select iscaptain from dbo.flyingdutchman where SailorId not in (select SailorId from inserted)
union all
select inserted.iscaptain as iscaptain from inserted
union all
select deleted.iscaptain as iscaptain from deleted
) as uniontable
having sum(case when uniontable.iscaptain = 1 then 1 else 0 end) <> 1)
if(@captainsum <> 1)
begin
throw 50000,'flying dutchman is cursed and needs a captain.',1;
end
end try
begin catch
if xact_state()<>0
rollback transaction;
throw;
end catch
end