SQL Server: триггер INSTEAD OF UPDATE: генерация динамического кода;вставленная таблица недоступна - PullRequest
0 голосов
/ 11 октября 2018

У меня есть следующее с триггером INSTEAD OF UPDATE, который динамически генерирует код и затем выполняет его.Проблема в том, что когда код выполняется, я всегда получаю сообщение об ошибке:

неверное имя объекта «вставлено»

Код триггера выглядит так:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER Trigger [dbo].[TACMasterLayouts_VersionVisibilityHandling_updates] 
ON [dbo].[TACMasterLayouts_VersionVisibilityHandling] 
INSTEAD OF UPDATE
AS
    IF @@rowcount = 0 
        RETURN; 

    SET NOCOUNT ON

    DECLARE @tableToUpdate AS NVARCHAR(MAX) = 'dbo.tacmasterlayouts';
    DECLARE @UpdateStatement AS NVARCHAR(MAX) 
    DECLARE @IdentityField AS NVARCHAR(MAX) = (SELECT Name 
                                               FROM sys.columns 
                                               WHERE [object_id] = OBJECT_ID('dbo.tacmasterlayouts') 
                                                  AND is_identity = 1)

    SET @UpdateStatement = 'update ' + @tableToUpdate + ' set ';

    DECLARE @Fields AS NVARCHAR(MAX)

    SELECT @Fields = COALESCE(@Fields + ', ', '') + @tableToUpdate + '.' + Name + ' = inserted.' + Name 
    FROM sys.columns 
    WHERE [object_id] = OBJECT_ID('dbo.tacmasterlayouts') 
      AND Name != @IdentityField;

    SET @UpdateStatement = @UpdateStatement + @fields

    SET @UpdateStatement = @UpdateStatement + ' FROM ' + @tableToUpdate + ', inserted'
    SET @UpdateStatement = @UpdateStatement + ' where ' + @tableToUpdate + '.' + @IdentityField + ' = inserted.' + @IdentityField

    EXECUTE sp_executesql @UpdateStatement

Динамический код выглядит следующим образом:

UPDATE TACMasterLayouts SET

 TACMasterLayouts.TACMasterLayoutName = inserted.TACMasterLayoutName, 
 TACMasterLayouts.TACMasterLayoutDestinationFileName = inserted.TACMasterLayoutDestinationFileName, 
 TACMasterLayouts.LayoutTypeCategoryId = inserted.LayoutTypeCategoryId, 
 TACMasterLayouts.LayoutTypeId = inserted.LayoutTypeId, 
 TACMasterLayouts.TACMasterLayoutDescription = inserted.TACMasterLayoutDescription, 
 TACMasterLayouts.TACMasterLayoutJasper = inserted.TACMasterLayoutJasper, 
 TACMasterLayouts.TACMasterLayoutJrxml = inserted.TACMasterLayoutJrxml, 
 TACMasterLayouts.TACMasterLayoutHtml = inserted.TACMasterLayoutHtml, 
 TACMasterLayouts.TACMasterLayoutDontClone = inserted.TACMasterLayoutDontClone, 
 TACMasterLayouts.TACMasterLayoutIsSubReport = inserted.TACMasterLayoutIsSubReport, 
 TACMasterLayouts.TACMasterLayoutVersion = inserted.TACMasterLayoutVersion, 
 TACMasterLayouts.TACMasterLayoutKey = inserted.TACMasterLayoutKey, 
 TACMasterLayouts.TACMasterLayoutTimestampLastModified = inserted.TACMasterLayoutTimestampLastModified, 
 TACMasterLayouts.TACMasterLayoutHash = inserted.TACMasterLayoutHash, 
 TACMasterLayouts.TACMasterLayoutTimestampLastCheckout = inserted.TACMasterLayoutTimestampLastCheckout,
 TACMasterLayouts.TACMasterLayoutCheckedOutByUserId = inserted.TACMasterLayoutCheckedOutByUserId,
 TACMasterLayouts.TACMasterLayoutIsCheckedIn = inserted.TACMasterLayoutIsCheckedIn, 
 TACMasterLayouts.TACMasterLayoutCheckedInByUserId = inserted.TACMasterLayoutCheckedInByUserId, 
 TACMasterLayouts.TACMasterLayoutCheckedOutFolderName = inserted.TACMasterLayoutCheckedOutFolderName 

FROM TACMasterLayouts, inserted
WHERE TACMAsterlayouts.TACMasterLayoutId = inserted.TACMasterLayoutId;

Подсказка:

Если я статически вводю динамически сгенерированный код в триггере, онработает отлично.так что сам код в порядке.

Вопрос: почему inserted недоступен в этой ситуации?И как это исправить?

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Когда выполняется динамический sql, он имеет собственную область видимости, например, вызов другой хранимой процедуры, поэтому он не может ссылаться на то, что находится в области действия триггера, например на вставленные, удаленные или локальные переменные и т. Д. Вы должны будете включить литеральное значение вдинамическая строка sql для требуемого значения ключа, а также быть готовым обработать более 1 вставленной строки, что вызвало срабатывание триггера.

0 голосов
/ 11 октября 2018

Поскольку приведенные выше ответы не дали мне желаемого решения, я продолжил копать и нашел следующее - крутое - решение (благодаря следующей статье: https://www.sqlteam.com/forums/topic.asp?TOPIC_ID=11318):

Если вам нужно пройти вставленныйтаблицу в динамический код SQL (для хранимой процедуры sp_executesql), выполните:

select * from inserted into #inserted

, а затем вы можете сразу получить к ней доступ в sp_executesql в разделе #inserted. Нет необходимости передавать это как параметр в sp_executesql.

окончательный рабочий код выглядит следующим образом:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Trigger [dbo].[TACMasterLayouts_VersionVisibilityHandling_updates] on [dbo].[TACMasterLayouts_VersionVisibilityHandling] INSTEAD OF update  
as 
 if @@rowcount = 0 return; 
 SET NOCOUNT ON

 Declare @tableToUpdate AS Nvarchar(max) = 'dbo.tacmasterlayouts';
 Declare @UpdateStatement AS Nvarchar(max)
 Declare @IdentityField as Nvarchar(max) = (SELECT Name FROM sys.columns WHERE [object_id] = OBJECT_ID(@tableToUpdate) and is_identity = 1)

 set @UpdateStatement = 'update ' + @tableToUpdate + ' set ';

 Declare @Fields AS Nvarchar(MAX)
 SELECT  @Fields = COALESCE(@Fields + ', ', '') + @tableToUpdate + '.' + Name + ' = #inserted.' + Name FROM sys.columns WHERE [object_id] = OBJECT_ID(@tableToUpdate) and Name != @IdentityField;

 set @UpdateStatement = @UpdateStatement + @fields

 set @UpdateStatement = @UpdateStatement + ' FROM ' + @tableToUpdate + ', #inserted'
 set @UpdateStatement = @UpdateStatement + ' where ' + @tableToUpdate + '.' + @IdentityField + ' = #inserted.' + @IdentityField

 select * into #inserted from inserted 

 EXECUTE sp_executesql @UpdateStatement
0 голосов
/ 11 октября 2018

Из того, что я обнаружил, похоже, что у вас, скорее всего, нет доступа к использованию таблицы inserted в динамическом SQL таким образом, но вы должны быть в состоянии выполнить то, что вы пытаетесь сделать, используяSQLCLR

Использование вставленных / удаленных таблиц в Dynamic SQL

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