我该如何纠正这个触发器?
How do i correct this trigger?
我在 table 上实现了一个触发器,它确保 table 不包含超过一行,其中一列的位值为 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 是一个 table 三列:
SailorId(int),SailorName(varchar),IsCaptain(bit)
和以下行:
执行查询时:
insert into dbo.flyingdutchman(Sailorname,IsCaptain)
values('Davy Jones',1)
我收到错误:
Msg 50000, Level 16, State 1, Procedure
FLYINGDUTCHMAN_NEEDS_A_CAPTAIN, Line xx FLYING DUTCHMAN IS CURSED AND
NEEDS A CAPTAIN.
我希望这个查询 运行 正常并且触发器不应该被触发。
因为这是一个 after
触发器,所以所有更改都已经在 table 中 - 您不需要查询 inserted
和 deleted
tables - 这就是你得到错误结果的原因。
您可以简单地这样做:
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;
可以简化为:
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
你的触发器总是触发,因为你的条件 if(@captainsum <> 1)
总是正确的
当您在子查询中的摘要等于 1 时,@captainsum
= null 因为您的 having 语句,那么您的变量为 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
我在 table 上实现了一个触发器,它确保 table 不包含超过一行,其中一列的位值为 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 是一个 table 三列:
SailorId(int),SailorName(varchar),IsCaptain(bit)
和以下行:
执行查询时:
insert into dbo.flyingdutchman(Sailorname,IsCaptain)
values('Davy Jones',1)
我收到错误:
Msg 50000, Level 16, State 1, Procedure FLYINGDUTCHMAN_NEEDS_A_CAPTAIN, Line xx FLYING DUTCHMAN IS CURSED AND NEEDS A CAPTAIN.
我希望这个查询 运行 正常并且触发器不应该被触发。
因为这是一个 after
触发器,所以所有更改都已经在 table 中 - 您不需要查询 inserted
和 deleted
tables - 这就是你得到错误结果的原因。
您可以简单地这样做:
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;
可以简化为:
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
你的触发器总是触发,因为你的条件 if(@captainsum <> 1)
总是正确的
当您在子查询中的摘要等于 1 时,@captainsum
= null 因为您的 having 语句,那么您的变量为 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