【问题标题】:SQL Server trigger operation with out cursor没有游标的 SQL Server 触发器操作
【发布时间】:2017-04-23 01:47:58
【问题描述】:

我有一个场景,我必须在每次 DML 操作后生成 SQL 脚本。我们有一个在每次插入、更新、删除之后运行的触发器。

它主要从 Inserted/Deleted 表中获取数据,为每一行生成一个 SQL 脚本,然后插入到另一个表中。

例如,如果我们插入

  1. 取所有插入的值
  2. 打开光标
  3. 对于每个插入的行,生成一个 SQL 脚本,该脚本将插入到另一个表中以进行审计
  4. 关闭光标。

对于 5 列的 10,000 行,此触发器需要将近 4-5 小时。列是intdatevarchar(100)

我们正在尝试替换触发器。需要相同的建议。

Set @syncScript = 'Insert Into table('

            Declare insertCursor Cursor Local Forward_Only For
            Select a, b, c From Inserted

            Open insertCursor

            Fetch Next From insertCursor Into @a, @b, @c

            While (@@Fetch_Status = 0)
            Begin
                Declare @valuesList varchar(max)

                Set @columnList = ''
                Set @paramsList = '['
                Set @valuesList = ''

                Select @columnList = @columnList + 'col6, ', @paramsList = @paramsList + '''' + COALESCE(dbo.ConvertFloatToVarchar(col6), 'NULL') + ''', ', @valuesList = @valuesList + '?, ' From Inserted I Where I.a= @a And I.b= @b And I.c= @c And 1 = 1
                Select @columnList = @columnList + 'col5, ', @paramsList = @paramsList + '''' + COALESCE(Convert(varchar(max), col5), 'NULL') + ''', ', @valuesList = @valuesList + '?, ' From Inserted I Where I.a= @a And I.b= @b And I.c= @c And 1 = 1
                Select @columnList = @columnList + 'col4, ', @paramsList = @paramsList + '''' + COALESCE(Convert(varchar(max), col4), 'NULL') + ''', ', @valuesList = @valuesList + '?, ' From Inserted I Where I.a= @a And I.b= @b And I.c= @c And 1 = 1
                Select @columnList = @columnList + 'col3, ', @paramsList = @paramsList + '''' + COALESCE(Convert(varchar(max), col3), 'NULL') + ''', ', @valuesList = @valuesList + '?, ' From Inserted I Where I.a= @a And I.b= @b And I.c= @c And 1 = 1
                Select @columnList = @columnList + 'col2, ', @paramsList = @paramsList + '''' + COALESCE(Convert(varchar(max), col2), 'NULL') + ''', ', @valuesList = @valuesList + '?, ' From Inserted I Where I.a= @a And I.b= @b And I.c= @c And 1 = 1
                Select @columnList = @columnList + 'col1, ', @paramsList = @paramsList + '''' + COALESCE(Convert(varchar(max), col1), 'NULL') + ''', ', @valuesList = @valuesList + '?, ' From Inserted I Where I.TraitValueMemberId = @a And I.ValueSetId = @b And I.LanguageCulture = @c And 1 = 1

                Set @columnList = SUBSTRING(@columnList, 1, Len(@columnList) - 1) + ') Values ('
                Set @valuesList = SUBSTRING(@valuesList, 1, Len(@valuesList) - 1) + ')'
                Set @paramsList = @paramsList + ']'
                Set @bigScript = (COALESCE(@syncScript, '') + COALESCE(@columnList, '') + COALESCE(@valuesList, ''))



                            Insert Into Log (CreatedDate, [Message]) Select GetDate(), 'tablename INSERT syncScript = ' + @bigScript +'paramsList = ' + COALESCE(@paramsList, '')

                Insert Into [dbo].[LogAudit] (GuidId, Query, Params, TableName, CreatedDate, Operation, UserId)
                Values ('00000000-0000-0000-0000-000000000000', @bigScript, @paramsList, @table, GetDate(), @operation, @debugUser)

                Fetch Next From insertCursor Into @a, @b, @c
            End

            Close insertCursor
            Deallocate insertCursor

在更新的情况下,我们连接插入和删除的表以生成更新脚本,如上所示。

【问题讨论】:

  • 您能解释一下为什么要使用游标和动态 SQL 吗?为什么不直接将 from 插入到表中?
  • 好吧,首先,您不需要逐行进行。由于您插入表格的内容基本上是静态的(始终是 col6、col5、col4... 等),因此您可以将其简化为:INSERT [Log] (CreatedDate, [Message]) SELECT GETDATE(), 'tablename INSERT syncScript = INSERT INTO TABLE (col6, col5, col4, col3, col2, col1) VALUES (''' + COALESCE(dbo.ConvertFloatToVarchar(col6), 'NULL') + ''', ''' + COALESCE(Convert(varchar(max), col5), 'NULL')... FROM inserted
  • @pmbaustin 我们生成的插入将同步到我们的移动设备并在那里进行更新处理

标签: sql sql-server cursor


【解决方案1】:

我使用 SET 操作而不是触发器解决了这个问题

INSERT Into [dbo].[LogAudit] (GuidId, Query, Params, TableName, CreatedDate, Operation, UserId)
            SELECT '00000000-0000-0000-0000-000000000000',  
                 'INSERT INTO Table(col6, col5, col4, col3, col2, col1) VALUES (?, ?, ?, ?, ?, ?)', 
            '[' +   '''' + COALESCE(dbo.ConvertFloatToVarchar(col6), 'NULL') + ''','  + '''' + COALESCE(Convert(varchar(max), col5), 'NULL') + ''', ' +  '''' + COALESCE(Convert(varchar(max), col4), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col3), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col2), 'NULL') + ''', ' +  '''' + COALESCE(Convert(varchar(max), col1), 'NULL') + ''', ' + ']', @table, GetDate(), @operation, @debugUser FROM Inserted

            -- Insert into Log
            Insert Into Log (CreatedDate, [Message]) Select GetDate(), 'MTDE_TraitValueMemberByLanguage_Sync INSERT 
                    syncScript = INSERT Into [dbo].[LogAudit (GuidId, Query, Params, TableName, CreatedDate, Operation, UserId) VALUES VALUES (?, ?, ?, ?, ?, ?)' + 
                    'paramsList = '  +  '[' +   '''' + COALESCE(dbo.ConvertFloatToVarchar(col6), 'NULL') + ''','  + '''' + COALESCE(Convert(varchar(max), col5), 'NULL') + ''', ' +  '''' + COALESCE(Convert(varchar(max), col4), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col3), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col2), 'NULL') + ''', ' +  '''' + COALESCE(Convert(varchar(max), col1), 'NULL') + ''', ' + ']' FROM Inserted

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 2010-12-11
    相关资源
    最近更新 更多