查看this answer有类似问题的人。对不起,如果这是一个长长的啰嗦:
SQL Server似乎通过映射不可代表的字符(没有合适的替代字符)到问号来将Unicode变为ASCII。要复制它,请尝试打开Character Map Windows程序(应该安装在大多数机器上),选择Arial作为字体并找到U + 034f“组合Grapheme连接器”。选择这个角色,复制到剪贴板,然后粘贴下面的单引号之间:
declare @t nvarchar(10)
set @t = '͏'
select rtrim(ltrim(@t)) -- we can try and trim it, but by this stage it's already a '?'
你会得到一个问号了,因为它不知道如何当它施放它代表了这个非ASCII字符到varchar
。为了强制它接受它为双字节字符(nvarchar
),您需要改为使用N''
,如前所述。上述引号前添加N
问号消失(但原来不可见字符在输出保存 - 和ltrim
,并如下面所示rtrim
将无法将其删除):
declare @t nvarchar(10),
@s varchar(10) -- note: single-byte string
set @t = rtrim(ltrim(N'͏')) -- trimming doesn't work here either
set @s = @t
select @s -- still outputs a question mark
进口数据绝对可以做到这个,我以前见过,像上面显示的那些人物特别难以诊断,因为你看不到他们!您需要创建某种清理流程来删除这些不打印邮件(以及其他任何垃圾邮件),并确保您在任何地方都使用nvarchar
,否则最终会出现此问题。更糟的是,那些虚幻的问号将成为真正的问号,你将无法与合法问号区分开来。
要查看字符代码你处理,你可以投为varbinary如下:
declare @t nvarchar(10)
set @t = N'͏test?'
select cast(@t as varbinary) -- returns 0x4F0374006500730074003F00
-- Returns:
-- 0x4F03 7400 6500 7300 7400 3F00
-- badchar t e s t ?
我们摆脱它:
declare @t nvarchar(10)
set @t = N'͏test?'
select cast(@t as varbinary) -- bad char
set @t = replace(@t COLLATE Latin1_General_100_BIN2, nchar(0x034f), N'');
select cast(@t as varbinary) -- gone!
注意,我不得不调换字节顺序从0x4f03
到0x034f
(同样的原因“t”在输出中出现为0x7400
,而不是0x0074
)。有关我们使用二进制排序规则的一些说明,请参阅this answer。
这是一种混乱,因为你不知道什么是肮脏的人物,他们可能是成千上万的可能性之一。一种选择是使用like
甚至unicode()
function迭代字符串,并放弃不在可接受字符列表中的字符串中的字符,但这可能会很慢。这可能是因为你的大部分坏字符都在字符串的开始或结尾,如果这是你认为可以做出的假设,那么这可能会加速这个过程。
根据我上面向您展示的内容,如果您需要导入大量数据,您可能需要在SQL Server外部或作为SSIS导入的一部分构建其他进程。如果您不确定这是否是最好的方法,那么最好在一个新问题中回答。
我希望有帮助。
如果您执行Ltrim(@temp)会怎么样? – Harry
注意:如果出于某种原因想要保持字符串不变,您应该设置@temp = N'mystring'(显式声明该字符串是unicode,即使您的变量是NVARCHAR,也应该这样做')而不是你目前正在做的事情。 – ZLK
看起来像一个字符集不匹配。 – Namphibian