我有几个列nvarchar(max)的表。我正在构建一个触发器,试图将单元格存储在sql_Variant中。 Nvarchar(max)不能存储在sql_variant中。如何检查它是否为nvarchar(max)然后将其转换为nvarchar(4000)以便我可以避免这种情况?
编辑:最有可能的错误发生在这里:
set @sql = 'select @audit_oldvalue=[' +@Item +'] from #tempTrigT';
因为@audit_oldvalue是sql_variant但#tempTrigT中的['+ @ Item +']可以是nvarchar(max)
如果我在输入表中编辑某些内容,则会出现此错误:
操作数类型clash 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'
--Define output parameter
set @ParmDefinition = '@OutString varchar(max) OUTPUT'
--Format sql
set @sql = 'Select @OutString = '
+ Substring(@sql,1 , len(@sql) -1) +
' From dbo.Forms i ' --Will need to be updated for target schema
+ ' inner join #tempTrigT d on
i.id = d.id' --Will need to be updated for target schema
--Execute sql and retrieve desired column list in output parameter
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'; --ERROR LINE
EXEC SP_EXECUTESQL @sql,N'@audit_oldvalue sql_variant OUTPUT',@audit_oldvalue OUTPUT -- If inserted @audit_oldvalue gets the new value
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
答案 0 :(得分:1)
您应该能够将其转换为VARCHAR(4000)。
Select @sql = @sql + '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 @sql = @sql + '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'