夏威夷语引号在 T-SQL 中与字符串函数一起使用时会出现一些奇怪的行为。 ... 其他角色也有同样的问题吗?
一些事情:
- 这不是夏威夷语“引号”:它是影响发音的“glottal stop”。
- 这不是“奇怪”的行为:这不是您所期望的。
-
这种行为并不是一个“问题”,虽然是的,还有其他角色表现出类似的行为。例如,以下字符(上方的 U+02DA 环)的行为会略有不同,具体取决于它位于字符的哪一侧:
SELECT REPLACE(N'a˚aa' COLLATE Latin1_General_100_CI_AS, N'˚a', N'_'); -- Returns a_a
SELECT REPLACE(N'a˚aa' COLLATE Latin1_General_100_CI_AS, N'a˚', N'_'); -- Returns _aa
现在,使用 SQL Server 2008 或更高版本的任何人都应该使用 100(或更高)级别的排序规则。他们在 100 系列中添加了很多排序权重和大写/小写映射,这些映射不在 90 系列中,或者没有编号的系列,或者大部分过时的 SQL Server 排序规则(名称以 SQL_ 开头的排序规则)。
这里的问题不在于它不等同于任何其他字符(在二进制排序规则之外),实际上它确实等同于另一个字符 (U+0312 Combining Turned Comma Above):
;WITH nums AS
(
SELECT TOP (65536) (ROW_NUMBER() OVER (ORDER BY @@MICROSOFTVERSION) - 1) AS [num]
FROM [master].sys.all_columns ac1
CROSS JOIN [master].sys.all_columns ac2
)
SELECT nums.[num] AS [INTvalue],
CONVERT(BINARY(2), nums.[num]) AS [BINvalue],
NCHAR(nums.[num]) AS [Character]
FROM nums
WHERE NCHAR(nums.[num]) = NCHAR(0x02BB) COLLATE Latin1_General_100_CI_AS;
/*
INTvalue BINvalue Character
699 0x02BB ʻ
786 0x0312 ̒
*/
问题在于这是一个“间距修饰符”字符,因此它会附加到它之前或之后的字符并修改其含义/发音,具体取决于您正在处理的修饰符字符。
根据Unicode Standard, Chapter 7 (Europe-I),第 7.8 节(修饰符字母),第 323 页(文档而非 PDF):
7.8 修饰字母
修饰符字母,在 Unicode 标准中使用的意义上,是通常与其他字母相邻书写并以某种方式修改其用法的字母或符号。它们没有正式组合标记(gc = Mn 或 gc = Mc),也没有以图形方式与它们修改的基本字母组合。他们本身就是基础角色。它们修改其他字母的意义更多的是它们的语义使用问题。它们通常倾向于像变音符号一样发挥作用,表示字母发音的变化,或以其他方式区分字母的用途。通常,这种变音符号修饰适用于修饰字母之前的字符,但修饰字母有时可能会修饰后面的字符。有时,修饰字母可能只是单独代表它自己的声音。
...
间距修饰字母:U+02B0–U+02FF
拼音用法。 此块中的大部分修饰字母是拼音修饰符,包括国际音标覆盖所需的字符。在许多情况下,修饰字母用于表示相邻字母的发音在某些方面有所不同——因此得名“修饰符”。它们还用于标记重音或音调,或者可能只是代表它们自己的声音。
下面的例子应该有助于说明。我正在使用 100 级排序规则,它需要区分重音(即名称包含 _AS):
SELECT REPLACE(N'ʻ' COLLATE Latin1_General_100_CI_AS, N'ʻ', N'_'); -- Returns _
SELECT REPLACE(N'ʻa' COLLATE Latin1_General_100_CI_AS, N'ʻ', N'_'); -- Returns _a
SELECT REPLACE(N'ʻaa' COLLATE Latin1_General_100_CI_AS, N'ʻ', N'_'); -- Returns _aa
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'ʻ', N'_'); -- Returns __aa
SELECT REPLACE(N'ʻaa' COLLATE Latin1_General_100_CI_AS, N'ʻa', N'_'); -- Returns ʻ__
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'ʻa', N'_'); -- Returns aʻ__
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'aʻ', N'_'); -- Returns _aa
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'aʻa', N'_'); -- Returns _a
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'a', N'_'); -- Returns aʻ__
SELECT REPLACE(N'אʻaa' COLLATE Latin1_General_100_CI_AS, N'א', N'_'); -- Returns אʻaa
SELECT REPLACE(N'ffʻaa' COLLATE Latin1_General_100_CI_AS, N'ff', N'_'); -- Returns ffʻaa
SELECT REPLACE(N'ffaa' COLLATE Latin1_General_100_CI_AS, N'ff', N'_'); -- Returns _aa
SELECT CHARINDEX(N'a', N'aʻa' COLLATE Latin1_General_100_CI_AS); -- 3
SELECT CHARINDEX(N'a', N'aʻa' COLLATE Latin1_General_100_CI_AI); -- 1
SELECT 1 WHERE N'a' = N'aʻ' COLLATE Latin1_General_100_CI_AS; -- (0 rows returned)
SELECT 2 WHERE N'a' = N'aʻ' COLLATE Latin1_General_100_CI_AI; -- 2
如果您需要以忽略其预期语言行为的方式处理此类字符,那么是的,您必须使用二进制排序规则。在这种情况下,请使用最新级别的排序规则,并使用BIN2 而不是BIN(假设您使用的是 SQL Server 2005 或更高版本)。含义:
- SQL Server 2000:
Latin1_General_BIN
- SQL Server 2005:
Latin1_General_BIN2
- SQL Server 2008、2008 R2、2012、2014 和 2016:
Latin1_General_100_BIN2
- SQL Server 2017 和更新版本:
Japanese_XJIS_140_BIN2
如果你好奇我为什么提出这个建议,请参阅:
Differences Between the Various Binary Collations (Cultures, Versions, and BIN vs BIN2)
并且,有关排序规则/Unicode/编码/等的更多信息,请访问:Collations Info