SQL触发器: Change nvarchar大小
SQL触发器: Change nvarchar大小
我有几个带有nvarchar(max)列的表格。我正在构建一个触发器,尝试将单元格存储在sql_Variant中。nvarchar(max)无法存储在sql_variant中。我如何检查它是否为nvarchar(max),然后将其转换为nvarchar(4000),以避免出现这个问题?
编辑:最可能的错误发生在这里:
set @sql = 'select @audit_oldvalue=[' +@Item +'] from #tempTrigT';
因为@audit_oldvalue是sql_variant,而[' +@Item +'] from #tempTrigT可以是nvarchar(max)。
如果我在输入表中进行编辑,我会得到这个错误:
操作数类型冲突,nvarchar(max)与sql_variant不兼容
表格结构:
输入表
输出表
我想要转换的代码:
Select * into #tempTrigT from (select * from deleted where @Action in ( 'U','D')) A UNION (select * from inserted where @Action ='I') Select @sql = @sql + 'Case when IsNull(i.[' + Column_Name + '],0) = IsNull(d.[' + Column_name + '],0) then '''' else ' + quotename(Column_Name, char(39)) + ' + '',''' + ' end +' from information_schema.columns where table_name = 'Forms' and column_name <>'rowguid' and column_name <>'modifieddate' --定义输出参数 set @ParmDefinition = '@OutString varchar(max) OUTPUT' --格式化sql set @sql = 'Select @OutString = ' + Substring(@sql,1 , len(@sql) -1) + ' From dbo.Forms i ' --需要根据目标模式进行更新 + ' inner join #tempTrigT d on i.id = d.id' --需要根据目标模式进行更新 --执行sql并在输出参数中检索所需的列列表 exec sp_executesql @sql, @ParmDefinition, @OutString OUT DECLARE @Items VARCHAR(max) set @Items = @OutString; DECLARE @Item VARCHAR(50) DECLARE @Pos INT DECLARE @Loop BIT SELECT @Loop = CASE WHEN LEN(@OutString) > 0 THEN 1 ELSE 0 END WHILE (SELECT @Loop) = 1 BEGIN SELECT @Pos = CHARINDEX(',', @OutString, 1) IF @Pos > 0 BEGIN SELECT @Item = SUBSTRING(@OutString, 1, @Pos - 1) SELECT @OutString = SUBSTRING(@OutString, @Pos + 1, LEN(@OutString) - @Pos) ---------------------------------- set @audit_field = @Item; set @sql = 'select @audit_oldvalue=[' +@Item +'] from #tempTrigT'; --错误行 EXEC SP_EXECUTESQL @sql,N'@audit_oldvalue sql_variant OUTPUT',@audit_oldvalue OUTPUT -- 如果插入,则@audit_oldvalue获取新值 set @sql = 'select @audit_value=i.[' +@Item +'] from dbo.Forms i inner join #tempTrigT d on i.id = d.id'; EXEC SP_EXECUTESQL @sql,N'@audit_value sql_variant OUTPUT',@audit_value OUTPUT if @Action = 'U' begin insert into [dbo].[AuditTrailForms]([TSid],[TSField],[OldValue],[NewValue],[changedate],[Change_Action],[Change_user],[Columns_Updated]) select id,@audit_field, @audit_oldvalue, @audit_value,getdate(),@Action, coalesce(ModifiedBy,suser_name()), @Items from inserted end END ELSE BEGIN SELECT @Item = @OutString SELECT @Loop = 0 END END
问题出现的原因是在执行SQL trigger时,出现了nvarchar大小改变的问题。解决方法是将nvarchar列转换为varchar(4000)。
首先,可以将nvarchar列直接转换为varchar(4000):
Select = + 'Case when IsNull(CAST(i.[' + Column_Name + '] AS VARCHAR(4000)),0) = IsNull(CAST(d.[' + Column_name + '] AS VARCHAR(4000)),0) then '''' else ' + quotename(Column_Name, char(39)) + ' + '',''' + ' end +' from information_schema.columns where table_name = 'Forms' and column_name <>'rowguid' and column_name <>'modifieddate'
或者,如果只想对特定的列执行转换(除非出于性能原因,否则可能不会出现问题):
Select = + 'Case when IsNull(' + CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN 'CAST(' ELSE '' END + 'i.[' + Column_Name + ']' + CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN ' AS VARCHAR(4000))' ELSE '' END + ',0) = IsNull(' + CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN 'CAST(' ELSE '' END + 'd.[' + Column_name + ']' + CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN ' AS VARCHAR(4000))' ELSE '' END + + ',0) then '''' else ' + quotename(Column_Name, char(39)) + ' + '',''' + ' end +' from information_schema.columns where table_name = 'Forms' and column_name <>'rowguid' and column_name <>'modifieddate'
然而,问题的提问者多次询问关于这段代码的问题,但是还没有接受任何一个答案。不确定提问者是否清楚实际需要的是什么。(如果不是在正确的地方提问,请原谅,我没有足够的声望,只能在自己的帖子上进行评论)
谢谢你们的回答。我提出了不同的问题,因为它们出现在同一段代码中,但是主题不同。当然我已经接受了问题。
我测试了第二个代码片段,但是我仍然收到相同的错误。我不想将所有东西都转换为varchar(4000),所以我选择了第二个代码片段。
tempTrigT是什么?你的帖子中没有包含创建该表的内容。
让我们在聊天中继续讨论。