Триггер SQL-сервера, возвращающий нулевые значения для удаленных значений полей строк - PullRequest
0 голосов
/ 18 июня 2019

Я столкнулся с проблемой, когда мне нужно сохранить копию записи в таблице «History» с исходными значениями поля обновленной записи перед тем, как я выполню обновление.

Я использую триггер для этого.Значение INSERTED триггера должно содержать значения полей строки после обновления, а DELETED должен отображать значения полей до обновления.

Однако всякий раз, когда запускается примерный код триггера, возврат SELECT всегда возвращает нуль для ArticleIDПараметры Title, StepContent и SortOrder.Однако, если бы я изменил строку кода, где он вытягивает из 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

1 Ответ

1 голос
/ 18 июня 2019

Итак, вот дикое предположение о том, как может выглядеть ваш триггер:

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 не применяется) для вашей таблицы истории, и как все эти строки должны относиться к своим исходным значениям ивозможно, в другие ряды «более высокого уровня».Более чем странно, что вам нужно получить идентификатор из таблицы истории, чтобы добавить в нее строки.Это означает, что у вас есть (или должен быть) триггер вставки.Если вы это сделаете, то, вероятно, также страдает от того же предположения в одной строке.

Но на самом деле не нужно "искать" идентификатор из таблицы истории, чтобы вставить больше строк.Я не видел такой необходимости в других ситуациях регистрации.Вы должны тщательно подумать о том, почему вы считаете это необходимым.

Название varchar (max)?Я бы тоже переосмыслил это.Возможно, это даст вам толчок к лучшему решению.

...