Избегайте рекурсии в триггере UPDATE с динамическим SQL - PullRequest
0 голосов
/ 04 июня 2018

Мы создаем защищенный триггер 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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...