【发布时间】:2019-06-18 15:17:27
【问题描述】:
我遇到了一个问题,我需要在进行更新之前将记录的副本保存到“历史”表中,其中包含更新记录的原始字段值。
我正在使用触发器来执行此操作。触发器 INSERTED 值应包含更新后的行字段值,而 DELETED 应显示更新前的字段值。
但是,每当示例触发器代码运行时,SELECT 的返回值始终为 ArticleID、Title、StepContent 和 SortOrder 参数返回 null。但是,如果我要更改从 DELETED 中提取的代码行以从 INSERTED 中提取,它就可以正常工作。
ALTER TRIGGER [dbo].[TRG_SaveHistory]
ON [dbo].[ArticleStep]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SortOrder INT,
@ArticleID INT,
@ArticleHistoryID INT,
@Title varchar(max),
@StepContent varchar(max);
--SELECT @SortOrder = SortOrder, @Title = Title, @StepContent = StepContent, @ArticleID = ArticleID FROM INSERTED;
SELECT TOP (1) @SortOrder = SortOrder, @Title = Title, @StepContent = StepContent, @ArticleID = ArticleID FROM DELETED WHERE @SortOrder != null;
SELECT TOP (1) @ArticleHistoryID = ID FROM dbo.ArticleHistory WHERE OriginalArticleID = @ArticleID ORDER BY ID DESC;
IF @SortOrder IS NOT Null AND @ArticleHistoryID IS NOT NULL
INSERT INTO [dbo].[ArticleStepHistory]
([ArticleHistoryID]
,[SortOrder]
,[Title]
,[StepContent])
VALUES
(@ArticleHistoryID
,@SortOrder
,@Title
,@StepContent);
END
当我改变这个时工作:
SELECT @SortOrder = SortOrder, @Title = Title, @StepContent = StepContent, @ArticleID = ArticleID FROM DELETED;
对此:
SELECT @SortOrder = SortOrder, @Title = Title, @StepContent = StepContent, @ArticleID = ArticleID FROM INSERTED;
这是我正在运行的更新查询:
UPDATE [dbo].[ArticleStep] SET [ArticleID] = 2 ,[SortOrder] = 3,[StepContent] = 'Changed Text' WHERE ID = 1
【问题讨论】:
-
如果您假设
inserted或deleted只有一行,那么您在触发器中犯了一个致命错误。你应该问另一个关于如何在 SQL Server 中正确编写触发器的问题。 -
请记住,删除和插入的行集可能不止一行。请务必将它们视为集合。
-
顺便说一句,从 2016 版本开始,您可以使用系统版本表,让 SQL Server 为您完成繁重的工作,而不是为此编写触发器。
-
一边;使用
sp_settriggerorder将触发顺序设置为'Last'是一个好主意。如果另一个触发器导致rollback,那么您还没有记录update, -
@matwonk 并非没有更新语句的示例,它更新的行(之前和之后),以及对目标的更好定义。讨论已知存在重大故障的触发器的逻辑确实没有意义 - 即单行假设。此外,您的逻辑取决于历史表中是否存在关联的行,以便将“有效”值插入同一个表中。我认为是时候重新开始并重新考虑你的整个方法了。至少,需要更多信息。
标签: sql sql-server database tsql database-trigger