当夏威夷语引号与字符串函数结合使用时,T-SQL 中的夏威夷语引号有一些奇怪的行为。 ...其他角色是否也遇到同样的问题?
一些东西:
- 这不是夏威夷语“引言”:这是“声门塞音 https://en.wikipedia.org/wiki/Hawaiian_phonology#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 组合上面的转逗号 https://unicode-table.com/en/0312/):
;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 标准,第 7 章(欧洲-I) https://www.unicode.org/versions/Unicode12.0.0/ch07.pdf,第 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
如果您好奇我为什么提出该建议,请参阅:
各种二进制排序规则之间的差异(文化、版本以及 BIN 与 BIN2) https://sqlquantumleap.com/2019/03/13/differences-between-the-various-binary-collations-cultures-versions-and-bin-vs-bin2/
并且,有关排序规则/Unicode/编码/等的更多信息,请访问:校对信息 https://collations.info/