如何让表触发获取当前行PK

时间:2013-07-11 15:16:52

标签: sql sql-server triggers

我正在尝试为表设置触发器以更新列“持续时间”,该列是行上开始日期和结束日期之间的持续时间。但是,每当我插入/更新列时,触发器都不起作用,因为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

2 个答案:

答案 0 :(得分: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作为计算[持久]列似乎是更好的选择......

ALTER TABLE event ADD Duration2 AS DATEDIFF(hour, [Date & Time Started],
[Date & Time Finished]) PERSISTED;

答案 1 :(得分: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])

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