这里说的右截断字符,是指类型为char或varchar的字段中,最后一个双字节字符(如汉字)由于字段宽度不够被切断为只剩下1个字节的字符,这个字符会被显示为乱码。sql server 2000及更早的版本,碰到要保存的字符串长度大于字段长度时,会把字符串截成字段的长度再保存,这个过程会出现右截断字符。升级到新版本后,这些右截断字符仍然存在,会妨碍数据导入/导出、bcp in/out等操作,因此需要把它们清除掉。
清除右截断字符的sql脚本如下所示。运行该脚本后生会产生清除右截断字符的sql命令,而不是直接进行清除右截断字符的操作。在正式执行这些sql命令前,可以先评估核实一下。
declare @dbname varchar(128) = 'targetdb';
if not exists (select * from sys.databases where name=@dbname)
begin
print 'error: database ''' + @dbname + ''' not exists.';
return;
end;
set nocount on;
declare @tabname varchar(128), @colname varchar(128), @sql nvarchar(4000);
declare @count int;
if object_id('tempdb..#tmp', 'u') is not null
drop table #tmp;
create table #tmp (tabname varchar(256), colname varchar(256));
set @sql = 'insert into #tmp ';
set @sql = @sql + 'select tabname=b.name, colname=a.name'
set @sql = @sql + ' from ' + @dbname + '.sys.columns a, '+ @dbname + '.sys.tables b'
set @sql = @sql + ' where a.object_id = b.object_id and b.is_ms_shipped=0'
set @sql = @sql + ' and a.system_type_id in (select system_type_id from '+ @dbname+ '.sys.types where name in (''char'', ''varchar''))';
--print @sql;
exec (@sql);
create clustered index index_tmp on #tmp (tabname, colname);
set @tabname = (select min(tabname) from #tmp);
while @tabname is not null
begin
set @colname = (select min(colname) from #tmp where tabname=@tabname);
while @colname is not null
begin
set @sql = 'select @count=count(*) from ' + @dbname + '.dbo.' + @tabname + ' ';
set @sql = @sql + ' where ' + @colname + ' is not null';
set @sql = @sql + ' and ' + @colname + ' <> ''''';
set @sql = @sql + ' and right(' + @colname + ', 1) <> '' ''';
set @sql = @sql + ' and cast(cast(right(' + @colname + ', 1) as varbinary) as varchar) = ''''';
--print @sql;
exec sp_executesql @sql, n'@count int output', @count output;
if @count > 0
begin
set @sql = 'update ' + @dbname +'.dbo.' + @tabname + ' set ';
set @sql = @sql + @colname + '= rtrim(cast(cast(' + @colname + ' as varbinary(8000)) as varchar(8000)))';
set @sql = @sql + ' where ' + @colname + ' is not null';
set @sql = @sql + ' and ' + @colname + ' <> ''''';
set @sql = @sql + ' and right(' + @colname + ', 1) <> '' ''';
set @sql = @sql + ' and cast(cast(right(' + @colname + ', 1) as varbinary) as varchar) = ''''';
print @sql;
end;
set @colname = (select min(colname) from #tmp where tabname=@tabname and colname>@colname);
end;
set @tabname = (select min(tabname) from #tmp where tabname>@tabname);
end;
set nocount off;