LIKE忽略魔术Unicode字符

时间:2014-12-18 19:30:43

标签: sql-server tsql unicode sql-like

SQL Server 2008 R2

 create table #test (c1 nvarchar(5) not null)

  insert into #test values 
  (N'aaa'),
  (nchar(65533)),
  (N'bbb')

  select * from #test where c1 like N'%�%'
  select * from #test where c1 like N'%'+nchar(65533)+N'%'

结果是

c1
----
aaa
�
bbb

为什么呢?我没有在MSDN中找到关于此案例的任何说明。

1 个答案:

答案 0 :(得分:2)

该角色(以及许多其他角色,取决于正在使用的归类版本)恰好没有定义排序权重。实际上没什么。因此,无论您有1个实例还是100个实例,除了二进制排序规则外,它都是不可见的。含义,以下WHERE谓词:

LIKE N'%' +  NCHAR(0xFFFD) + N'%'

LIKE N'%' +  NCHAR(0xFFFD) +  NCHAR(0xFFFD) + N'%'

LIKE N'%' +  NCHAR(0xFFFD) +  NCHAR(0xFFFD) +  NCHAR(0xFFFD) + N'%'

等等,都等同于以下内容:

LIKE N'%%'

这就是你返回所有3行的原因。

这并不意味着此字符应该没有排序权重。它实际上在Unicode中被定义为具有权重,但由于某种原因,Microsoft已经留下了相当多的字符而没有任何排序权重(尽管每个新的Collat​​ion版本缺少排序权重的字符总数正在减少,最新的是版本140排序规则,与SQL Server 2017一起提供,仅适用于日语排序规则。)

对于没有排序权重的任何字符,匹配它的唯一方法是使用二进制排序规则。二进制排序规则以_BIN_BIN2结尾,但仅使用_BIN2排序规则,因为它们排序正确,而较旧的_BIN排序规则则不然。例如:

SELECT * FROM #test WHERE c1 LIKE N'%�%' COLLATE Latin1_General_100_BIN2;

返回:

  

C1
  ----
  

另外,我测试了以下内容,他们返回了所有3行:

  • Latin1_General_CS_AS_KS_WS
  • Latin1_General_100_CS_AS_KS_WS_SC

所以,以下应该是好的:

  • Latin1_General_BIN2
  • Latin1_General_100_BIN2

此外,最好使用可用于您尝试使用的排序规则的最高排序规则版本。例如,使用Latin1_General_100_*代替Latin1_General_*,依此类推。使用以下查询查找实例上可用的排序规则:

SELECT col.*
FROM   sys.fn_helpcollations() col
ORDER BY col.[name];