Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server触发器为已删除的行字段值返回空值_Sql_Sql Server_Database_Tsql_Database Trigger - Fatal编程技术网

SQL Server触发器为已删除的行字段值返回空值

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 [

我遇到了一个问题,在我进行更新之前,我需要使用更新记录的原始字段值将记录的副本保存到“History”表中

我用触发器来做这个。触发器插入值应包含更新后的行字段值,删除值应显示更新前的字段值

但是,每当示例触发器代码运行时,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

下面是一个关于触发器的粗略猜测:

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没有更新语句的示例,它更新的行(之前和之后)以及更好的目标定义。讨论已知存在重大故障的触发器的逻辑实际上没有意义,这是单行假设。此外,您的逻辑取决于历史记录表中是否存在关联行,以便将“有效”值插入到同一个表中。我认为是时候重新开始,重新考虑你的整个方法了。至少,还需要更多的信息。