Sql server 2008 无法创建替代触发器
我有两个SQLServer2008表:Schedules(父表)和ScheduleResults(子表) 及 逻辑是,在插入/更新/删除子项之后,我查看父项的所有子项。如果其中任何一个具有IsEndOfRun=1,则父计划记录状态变为“DEA”,否则变为“ACT”。如果没有找到,它仍然会转到“ACT” 这是我的触发器:Sql server 2008 无法创建替代触发器,sql-server-2008,tsql,Sql Server 2008,Tsql,我有两个SQLServer2008表:Schedules(父表)和ScheduleResults(子表) 及 逻辑是,在插入/更新/删除子项之后,我查看父项的所有子项。如果其中任何一个具有IsEndOfRun=1,则父计划记录状态变为“DEA”,否则变为“ACT”。如果没有找到,它仍然会转到“ACT” 这是我的触发器: CREATE TRIGGER ScheduleResultsStatus ON [ScheduleResults] AFTER INSERT, UPDATE, DELETE AS
CREATE TRIGGER ScheduleResultsStatus
ON [ScheduleResults] AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
DECLARE @ScheduleID int
DECLARE @IsEORSum int
SELECT @ScheduleID=ScheduleID FROM inserted
SELECT @IsEORSum=COUNT(*) FROM ScheduleResults WHERE ScheduleID=@ScheduleID AND IsEndOfRun=1
IF @IsEORSum=0
BEGIN
-- There are no EndOfRun results. Schedule should be active
UPDATE Schedules SET Status='ACT' WHERE ID=@ScheduleID
END
ELSE
BEGIN
-- There is at least 1 record with IsEndOfRun=True. Schedule should be DEACTIVATED
UPDATE Schedules SET Status='DEA' WHERE ID=@ScheduleID
END
插入后效果完美。更新后的作品完美。删除后不起作用。触发器名称上有一条歪歪扭扭的警告信息:
无法创建而不是删除触发器。这是因为表有一个带有级联删除的外键
我最初的定义在ScheduleID列上有一个ON DELETE CASCADE子句。我移除了它,但没有成功。另外,正如您所看到的,我正在创建一个AFTER触发器,而不是一个INSTEAD-of触发器。所以现在我的问题是。。。我如何调整触发器和/或FK约束,以便处理引用完整性和删除子场景
感谢所有SQL Server向导的帮助。感谢前面的评论。它引发了一些想法,我不仅能够让它工作,而且代码在使用集合时更简单。以下是子孙后代的代码:
CREATE TRIGGER ScheduleResultsStatus
ON [ScheduleResults] AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
UPDATE Schedules SET Status='ACT' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN deleted ON Schedules.ID=deleted.ScheduleID)
UPDATE Schedules SET Status='DEA' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN inserted ON Schedules.ID=inserted.ScheduleID WHERE IsEndOfRun=1)
UPDATE Schedules SET Status='ACT' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN inserted ON Schedules.ID=inserted.ScheduleID Group BY Schedules.ID HAVING SUM(CONVERT(int, IsEndOfRun))=0)
GO
谢谢你之前的评论。它引发了一些想法,我不仅能够让它工作,而且代码在使用集合时更简单。以下是子孙后代的代码:
CREATE TRIGGER ScheduleResultsStatus
ON [ScheduleResults] AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
UPDATE Schedules SET Status='ACT' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN deleted ON Schedules.ID=deleted.ScheduleID)
UPDATE Schedules SET Status='DEA' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN inserted ON Schedules.ID=inserted.ScheduleID WHERE IsEndOfRun=1)
UPDATE Schedules SET Status='ACT' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN inserted ON Schedules.ID=inserted.ScheduleID Group BY Schedules.ID HAVING SUM(CONVERT(int, IsEndOfRun))=0)
GO
旁注:看到这条语句
SELECT@ScheduleID=ScheduleID FROM inserted
,您似乎认为每行将调用一次触发器-事实并非如此;每个语句将调用一次触发器,如果该语句影响多行,则插入的伪表中将包含多行。您需要以这样一种方式编写触发器代码,即它可以处理插入的中的多行-您的代码当前无法这样做。您真的需要存储此状态吗?-在检索过程中计算它似乎是一件简单的事情(如果愿意,您可以创建一个包含逻辑的视图),而且,除了marc_的注释之外,当您只想确定存在与否时,不要COUNT()
EXISTS()
存在是有原因的。另外:插入的表在INSERT和UPDATE语句期间存储受影响行的副本。在insert或update事务期间,新行同时添加到插入表和触发器表中。插入表中的行是触发器表中新行的副本。因此,在delete的情况下,您的select将永远不会返回任何内容。marc_s,正确,我需要调整触发器以处理集合,而不是单个记录。旁注:看到此语句select@ScheduleID=ScheduleID FROM inserted
,您似乎认为触发器将每行调用一次-情况并非如此;每个语句将调用一次触发器,如果该语句影响多行,则插入的伪表中将包含多行。您需要以这样一种方式编写触发器代码,即它可以处理插入的中的多行-您的代码当前无法这样做。您真的需要存储此状态吗?-在检索过程中计算它似乎是一件简单的事情(如果愿意,您可以创建一个包含逻辑的视图),而且,除了marc_的注释之外,当您只想确定存在与否时,不要COUNT()
EXISTS()
存在是有原因的。另外:插入的表在INSERT和UPDATE语句期间存储受影响行的副本。在insert或update事务期间,新行同时添加到插入表和触发器表中。插入表中的行是触发器表中新行的副本。因此,如果删除,您的选择将永远不会返回任何内容。marc_,正确,我需要调整触发器以处理集合,而不是单个记录。
CREATE TRIGGER ScheduleResultsStatus
ON [ScheduleResults] AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
UPDATE Schedules SET Status='ACT' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN deleted ON Schedules.ID=deleted.ScheduleID)
UPDATE Schedules SET Status='DEA' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN inserted ON Schedules.ID=inserted.ScheduleID WHERE IsEndOfRun=1)
UPDATE Schedules SET Status='ACT' WHERE ID IN (SELECT DISTINCT Schedules.ID FROM Schedules INNER JOIN inserted ON Schedules.ID=inserted.ScheduleID Group BY Schedules.ID HAVING SUM(CONVERT(int, IsEndOfRun))=0)
GO