我该如何纠正触发条件?

时间:2019-04-07 09:19:35

标签: sql-server tsql database-trigger

我已经在一个表上实现了一个触发器,以确保该表不包含多于一行的数据,其中一列的位值为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)

以及以下各行:

enter image description here

执行查询时:

insert into dbo.flyingdutchman(Sailorname,IsCaptain)
values('Davy Jones',1)

我得到了错误:

  

消息50000,级别16,状态1,过程   FLYINGDUTCHMAN_NEEDS_A_CAPTAIN,第XX行FULLING DUTCHMAN被诅咒,   需要一个船长。

我希望此查询运行正常,并且不会触发触发器。

3 个答案:

答案 0 :(得分:2)

由于这是一个after触发器,因此所有更改已在表中-您无需查询inserteddeleted表-这就是您获得错误的结果。

您可以简单地执行以下操作:

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