今天是我的问题:我们将一些信息从文本文件加载到SQL Server表中。问题是,对于一个字段,我意识到字符串值有点奇怪。
当我使用SQL Server客户端2008或之前的查询表时,我得到了这个结果集:
即使我尝试运行如下所示的查询,结果集也是空的:
select REPLACE(LTRIM(RTRIM(cust_po)), ' ', ' ')
from dbo.test_char
where cust_po like '%076929%'
奇怪的是:使用SQL Server 2016,只是打开表看起来很正常,尽管查询也没有返回任何结果:
现在,根据@SolomonRutzky的一些指示,我已经执行了下面的查询以获得varbinary中的结果
新结果为:0x300037003600390032003900BC05BC05BC05BC05BC05BC05BC05BC05BC05
怎么可能把它当作一个没有奇怪的字符或空格的varchar,或者在哪里呢?
答案 0 :(得分:2)
现在已发布数据的VARBINARY
表示,问题更加清晰。
正如我们所看到的,带有“奇数”字符的两行是:
0x300037003600390032003900BC05BC05BC05BC05BC05BC05BC05BC05BC05
此列为NVARCHAR
,表示编码为UTF-16 Little Endian。作为UTF-16意味着我们查看每个2字节的块(字符将是这些2字节块的1或2组),而Little Endian意味着每个2字节块中的字节的顺序相反。意思是,第一个字符是3000
(2个字节),这相当于代码点U + 0030,即0
。下一个字符是3700
,即代码点U + 0037,即7
。依此类推3900
,这是值中的最终9
。
然后我们得到9组BC05
,即Code Point U + 05BC,Hebrew Point Dagesh or Mapiq。这就是它变得有趣的地方,因为这里有三个不同的事情:
0
左侧都有一个小点。要查看此操作,请执行以下查询:
SELECT N'4 11' + REPLICATE(NCHAR(0x05BC), 10) + N' 88 f ';
返回:
注意第二个1
左侧的单个点。即使字符串中有10个(由于REPLICATE
),也只有一个点。嗯,这就是我的浏览器显示的内容,如下图所示:
然而,我在结果网格中看到了以下内容:
注意点位于第一个,而不是第二个1
的左侧,以及11
与88
之间f
的位置,< / p>
而且,如果我从结果网格中复制并粘贴到查询编辑器中,我会看到:
请注意,有几个红点。
where cust_po like '%076929%'
没有返回任何行?这是由于字符串比较做了它应该做的事情并应用语言规则。字节的顺序并不重要,重要的是如何从人类阅读角度查看渲染字符串。由于这个特殊字符是一个组合字符,它不会出现在前面的字符之后,它是它的一部分。这意味着,9
值中的第二个076929
不再是9
,而是9
+ Dagesh。
SELECT 1 WHERE
N'123' + REPLICATE(NCHAR(0x05BC), 5) LIKE N'%123' + REPLICATE(NCHAR(0x05BC), 4) + N'%';
-- no rows returned
SELECT 2 WHERE
N'123' + REPLICATE(NCHAR(0x05BC), 5) LIKE N'%123' + REPLICATE(NCHAR(0x05BC), 5) + N'%';
-- 2
SELECT 3 WHERE N'9' + NCHAR(0x05BC) = N'9'
-- no rows returned
假设此U + 05BC字符是数据中唯一的问题,您可以进行简单的替换。您已尝试过此操作,但REPLACE
找不到匹配项。发生这种情况时,您需要使用二进制排序规则,如下所示:
SELECT REPLACE(N'4 11' + REPLICATE(NCHAR(0x05BC), 5) + N' 88 f ',
NCHAR(0x05BC) COLLATE Latin1_General_100_BIN2,
N'~');
-- 4 11~~~~~ 88 f
答案 1 :(得分:1)
首先 - 当你让@solomon Rutzky查看你的代码时,你会得到很好的帮助;)
我目前没有此版本的NVarchar,但如果您只想要列中的数值,则可以使用Blob。解决方案看起来像这样。
-- sample data with a couple characters to screw you up.
DECLARE @table TABLE (somestring nvarchar(100));
INSERT @table
SELECT CONCAT(NCHAR(365), '123') UNION ALL
SELECT CONCAT(CHAR(0), '789');
-- solution
SELECT *
FROM @table t
CROSS APPLY dbo.DigitsOnlyEE(t.somestring);
结果:
somestring DigitsOnly
------------ ------------
ŭ123 123
789 789