SQL Server触发器为已删除的行字段值返回空值
我遇到了一个问题,在我进行更新之前,我需要使用更新记录的原始字段值将记录的副本保存到“History”表中 我用触发器来做这个。触发器插入值应包含更新后的行字段值,删除值应显示更新前的字段值 但是,每当示例触发器代码运行时,SELECT的返回总是为ArticleID、Title、StepContent和SortOrder参数返回null。然而,如果我将代码行从DELETED改为INSERTED,它就可以正常工作SQL Server触发器为已删除的行字段值返回空值,sql,sql-server,database,tsql,database-trigger,Sql,Sql Server,Database,Tsql,Database Trigger,我遇到了一个问题,在我进行更新之前,我需要使用更新记录的原始字段值将记录的副本保存到“History”表中 我用触发器来做这个。触发器插入值应包含更新后的行字段值,删除值应显示更新前的字段值 但是,每当示例触发器代码运行时,SELECT的返回总是为ArticleID、Title、StepContent和SortOrder参数返回null。然而,如果我将代码行从DELETED改为INSERTED,它就可以正常工作 ALTER TRIGGER [dbo].[TRG_SaveHistory] ON [
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
下面是一个关于触发器的粗略猜测:
alter trigger dbo.TRG_SaveHistory
on dbo.ArticleStep after update
as
begin
set nocount on;
if not exists (select * from deleted)
return;
with cte as (
select max(ID) as HistoryID, OriginalArticleID
from dbo.ArticleHistory
group by OriginalArticleID)
insert dbo.ArticleStepHistory (ArticleHistoryID, SortOrder, Title, StepContent)
select cte.HistoryID, deleted.SortOrder, deleted.Title, deleted.StepContent
from deleted inner join cte
on deleted.ArticleID = cte.OriginalArticleID;
end;
这完全是猜测。您可能需要对其进行调整,以防出现小的语法错误,因为我没有您的数据库,并且是使用记事本编写的。如果您正在编写tsql代码,您应该能够(并且应该能够)纠正一些小错误
了解ArticleStep的主键、历史记录表的主键和外键(即使没有强制执行FK)以及所有这些行与它们的原始值以及可能与其他“更高级别”行的关系非常重要。您需要从历史记录表中检索一个ID以便向其中添加行,这一点非常奇怪。这意味着您有(或应该有)一个插入触发器。如果您这样做,它可能也会受到相同的单行假设的影响
但实际上,不必为了插入更多行而从历史记录表中“查找”id。在其他日志记录情况下,我没有看到这种需求。你应该仔细考虑为什么你认为这是必要的
标题是varchar(最大值)?我也会重新考虑。也许这会推动你找到更好的解决方案 如果假定
插入的
或删除的
只有一行,则触发器中会出现致命错误。您应该询问另一个有关如何在SQL Server中正确编写触发器的问题。请记住,已删除和插入的行集中可能有多行。请确保将它们视为sets.BTW,从2016版开始,您可以使用系统版本表,让SQL Server为您完成繁重的工作,而不是为此编写触发器;使用将日志触发器的触发顺序设置为“Last”
,这是一个好主意。如果另一个触发器导致回滚
,那么您还没有记录更新
,@matwonk没有更新语句的示例,它更新的行(之前和之后)以及更好的目标定义。讨论已知存在重大故障的触发器的逻辑实际上没有意义,这是单行假设。此外,您的逻辑取决于历史记录表中是否存在关联行,以便将“有效”值插入到同一个表中。我认为是时候重新开始,重新考虑你的整个方法了。至少,还需要更多的信息。