0

我正在尝试为表设置触发器以更新列“持续时间”,即该行的开始日期和结束日期之间的持续时间。但是,每当我插入/更新列时,触发器都不起作用,因为 SCOPE_INDENTITY() 一直返回 null。我怎样才能解决这个问题?

ALTER TRIGGER [dbo].[CalcDuration]
ON [dbo].[Event]
AFTER INSERT, UPDATE, DELETE 
AS

DECLARE @STARTED datetime
DECLARE @FINISHED datetime
DECLARE @ID int

SELECT @ID = SCOPE_IDENTITY()

SELECT @STARTED  = [Date & Time Started] FROM  dbo.Event WHERE [Event ID] = @ID
SELECT @FINISHED = [Date & Time Finished] FROM dbo.Event WHERE [Event ID] = @ID

UPDATE dbo.Event 
SET Duration = DATEDIFF (  hour, @STARTED, @FINISHED )
WHERE [Event ID] = @ID
4

2 回答 2

1

如果您坚持after为此使用触发器(注意:不需要AFTER DELETE),您可以这样做

CREATE TRIGGER ai_event
ON event AFTER INSERT,UPDATE
as
BEGIN
UPDATE event 
SET  Duration  = DATEDIFF(hour, i.[Date & Time Started],i.[Date & Time Finished])
from event e 
INNER JOIN INSERTED i ON (i.id = e.id)

END;

但是,Duration在这种情况下,作为计算的 [persisted] 列似乎是一个更好的选择......

ALTER TABLE event ADD Duration2 AS DATEDIFF(hour, [Date & Time Started],
[Date & Time Finished]) PERSISTED;
于 2013-07-11T15:34:11.853 回答
1

SCOPE_INDENTITY()仅返回当前范围内最后插入的标识值,因此如果在触发器内部使用它,它只会在触发器中执行插入操作后返回值 - 这里不是这种情况,因此返回 NULL。

我想您正在尝试获取插入/更新值的 ID,在这种情况下INSERTED可以使用表。

接下来,假设您的触发器仅在单行上工作,您犯了一个大错误,但通常情况并非如此,因为 UPDATE 和 INSERT 可以在多行上工作。INSERTED幸运的是,表包含所有插入/更新的行。

所以你的触发器应该是这样的:

UPDATE e
SET e.Duration = DATEDIFF (hour, e.[Date & Time Started], e.[Date & Time Finished])
FROM dbo.Event e
INNER JOIN INSERTED i on e.[Event ID] = i.[Event ID]

最后,还要指出这完全是不必要的触发器使用。使用计算列也可以(并且应该)这样做。因此,如果您只是将列更改为:

ALTER TABLE  dbo.Event
ALTER COLUMN [Duration] AS DATEDIFF(hour, [Date & Time Started], [Date & Time Finished])

您将始终拥有正确的持续时间,而无需触发。

于 2013-07-11T15:34:12.077 回答