У меня небольшая проблема с триггером обновления в SQL Server 2008 R2. Я установил триггер для регистрации изменений в таблице журналов. Это работает отлично для меня, но не тогда, когда я обновляю несколько строк.Сложный триггер обновления SQL Server с несколькими строками
CREATE TRIGGER [dbo].[TR_CompaniesUpdated]
ON [dbo].[Companies]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@Return NVARCHAR(MAX), -- Is the JSON of the data
@ParameterSQL VARCHAR(MAX), -- Is the select we want to retreive in JSON format
-- Data from of the row updated
@ID INT,
@StatusID SMALLINT,
-- Old data from of the row
@StatusID2 SMALLINT
-- Declare the cursor
DECLARE InsertedCursor CURSOR FAST_FORWARD FOR
SELECT [ID], [StatusID] FROM INSERTED
-- Create the temporary table with logs so we'll need to do only one insert after this
CREATE TABLE #tempLog(
[ID] [int] NOT NULL,
[Data] [nvarchar](max) NOT NULL,
[ActionID] [int] NOT NULL,
[DtCreated] [datetime] NOT NULL,
[CreatedBy] [int] NOT NULL)
-- Save updated values into variables
OPEN InsertedCursor
FETCH NEXT FROM InsertedCursor
INTO @ID, @StatusID
WHILE @@fetch_status = 0
BEGIN
-- Save old values into variables
SELECT
@StatusID2 = [StatusID]
FROM DELETED
WHERE [ID] = @ID
SELECT * INTO #tempTable
FROM DELETED
WHERE [ID] = @ID
-- Build the select only to et the changed data
SET @ParameterSQL = 'SELECT '
IF (ISNULL(@StatusID, '') != ISNULL(@StatusID2, '')) SET @ParameterSQL = @ParameterSQL + '[StatusID],'
IF (@ParameterSQL != 'SELECT ')
BEGIN
-- Update the modified date
UPDATE [dbo].[AssessedLevelCostCentre]
SET [DtModified] = GETDATE()
WHERE [ID] = @ID
SET @ParameterSQL = SUBSTRING(@ParameterSQL, 0, LEN(@ParameterSQL)) + ' FROM #tempTable'
-- Execute the JSON function to get the result in JSON format
EXEC [dbo].[GetJSON] @ParameterSQL, @Return = @Return OUTPUT
-- Insert the Change Log with the old data
INSERT INTO #tempLog
SELECT
[ID] AS [ID],
@Return AS [Data],
[ActionID] AS [ActionID],
CASE
WHEN [DtModified] IS NULL
THEN [DtCreated]
ELSE [DtModified]
END AS [DtModified],
CASE
WHEN [ModifiedBy] IS NULL
THEN [CreatedBy]
ELSE [ModifiedBy]
END AS [CreatedBy]
FROM #tempTable
END
ELSE
BEGIN
UPDATE [dbo].[AssessedLevelCostCentre]
SET [ModifiedBy] = (SELECT [ModifiedBy] FROM #tempTable)
WHERE [ID] = @ID
END
DROP TABLE #tempTable
-- Advance the Cursor
FETCH NEXT FROM InsertedCursor
INTO @ID, @StatusID
END
CLOSE InsertedCursor
DEALLOCATE InsertedCursor
-- Insert the Change Log with the old data
INSERT INTO [dbo].[AssessedLevelsCostCentersLogs]
SELECT *
FROM #tempLog
DROP TABLE #tempLog
END
Как вы можете видеть, у меня есть хранимая процедура, чем возвращает мне данные в формате JSON, проблема, чем хранимая процедура получения данных из запроса, и я не могу передать делеции или инсерциям таблицы, это Причина, по которой я использовал временную таблицу, которая, похоже, делает трюк, но добавляет предложение ID.
ОБНОВЛЕНО
Я обновил код, теперь у меня есть курсор, а как я могу видеть, производительность это очень медленно. Мне это нужно, потому что я не могу изменить приложение для создания JSON, и я думаю, что я запускаю, как это будет работать нормально. У кого-нибудь есть идея или как улучшить производительность этого?
Вы должны перестроить свой триггер - я бы рекомендовал ** НЕ ** выполнять любую обработку длины (например, генерировать JSON, используя хранимую процедуру) внутри триггера. Триггер срабатывает много раз, и вы не можете контролировать, как часто и когда он срабатывает. Вы должны попытаться ограничить триггер ** абсолютным минимумом ** - просто введите запись в таблицу или что-то еще - не более. Если вам нужно выполнить дополнительную обработку - сделайте это в отдельной асинхронной задаче, например. регулярно работая как запланированное задание SQL. Сделайте ** НЕ ** перегружайте триггеры! Это будет ** убить ** вашу систему! –