Мы создаем защищенный триггер INSTEAD OF UPDATE для мониторинга и управления обновлениями нескольких таблиц (большинство таблиц MasterData системы, около 150 из них).Поэтому, насколько это возможно (установка, обновления), мы стараемся сделать код максимально пригодным для повторного использования (без жестких кодов имен полей или таблиц).
Для управления «актуальной» версией строки,существует поле _ACTIVE, и оно уменьшается для каждой новой версии (строка ACTIVE получает ACTIVE = 1).Извините, мы не можем использовать функцию временных таблиц из-за обратной совместимости (на основе этой функции создается множество бизнес-логики)
Логика обновления включает обработку строк OLD и NEW до того, как они повлияют на таблицу, и как только все будетлечится, обновляется таблица;не только затронутые строки, но и все с одинаковыми полями ключа уникальности (идентификация полей уникальности также должна выполняться динамически; в следующем примере предложение where динамически создается на основе переменной @toWhereOnClause)
«Настоящая» таблица переносит два действия: сначала вставляется куча новых строк с _ACTIVE = 2, во-вторых, все строки, которые необходимо обновить, получают _ACTIVE - = 1, в результате чего самой новой версии строки присваивается значение 1 * 1007.*
Проблема возникает из-за того, что это второе действие, обновление, необходимо создавать динамически, чтобы избежать ввода имени таблицы, и установить @toWhereOnClause вручную.И это снова вызывает TRIGGER, и поскольку он является динамическим, мы считаем, что TRIGGER_NESTLEVEL () = 1
структура кода не выглядит следующим образом:
CREATE OR ALTER TRIGGER [schema].[triggerName] ON [schema].table
INSTEAD OF UPDATE
AS
BEGIN
SET @tableName = '[schema].[table]' // only line to modify for diferent tables
//TRIGGER PREPARATION
SET @schema = (SELECT SUBSTRING(@tableName, 1, (CHARINDEX('].', @tableName))))
SET @table = (SELECT SUBSTRING(@tableName, (CHARINDEX('[', @tableName, 3)), LEN(@tableName)))
SET @fieldNameS = (SELECT + ',' + QUOTENAME(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @schema
AND TABLE_NAME = @table
ORDER BY ORDINAL_POSITION
FOR XML path(''));
SET @uniqueFieldSelector = (SELECT +' AND LeftTable.'+ COLUMN_NAME + ' = #INSERTED.' + COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = @tableName
AND COLUMN_NAME NOT LIKE '%Active%'
FOR XML PATH(''))
SET @toWhereOnClause = (SELECT (SUBSTRING(@uniqueFieldSelector, 5, LEN(@uniqueFieldSelector))))
// DUPLICATE TRIGGER TABLES INTO TEMP TABLE TO WORK ON NEW AND OLD LINES
SELECT * INTO #INSERTED FROM INSERTED -- Can't modify logic table values (INSERTED), we put it in a temp table
SELECT * INTO #DELETED FROM DELETED
// SEVERAL INSTRUCTIONS TO TREAT THE OLD AND NEW LINES (not shown here) AND CALCULATE IF THE UPDATE IS LEGAL (@CONTINUE_TRIGGER)
...
// REAL UPDATE
IF TRIGGER_NESTLEVEL() = 1 AND @CONTINUE_TRIGGER = TRUE
--/1100384/kak-predotvratit-povtorenie-triggera-bazy-dannyh
BEGIN
SET @statementINSERT = N'INSERT INTO' + @tableName + '( ... )
SELECT ... FROM #INSERTED ';
EXECUTE sp_executesql @statementINSERT
SET @statementUPDATE = N'UPDATE TheRealTable
SET TheRealTable._ACTIVE -= 1
FROM ' + @tableName + ' AS TheRealTable
INNER JOIN #INSERTED ON ' + @toWhereOnClause;
EXECUTE sp_executesql @statementUPDATE
END
END
да,мы знаем, что это сложно, но унаследованное не дает много вариантов.
SO:
Есть ли способ избежать триггера dynamicSQL снова TRIGGER ??
(система работает на WindowsServer и экземплярах Azure, все с совместимостью не менее 120)