特殊字符(夏威夷人'Okina)导致奇怪的弦乐行为

bde*_*ere 14 t-sql sql-server unicode collation

当将夏威夷报价与字符串函数结合使用时,在T-SQL中有一些奇怪的行为。这里发生了什么?我想念什么吗?其他角色也会遭受同样的问题吗?

SELECT UNICODE(N'?') -- Returns 699 as expected.

SELECT REPLACE(N'"?', '"', '_') -- Returns "?, I expected _?

SELECT REPLACE(N'a?', 'a', '_') -- Returns a?, I expected _?

SELECT REPLACE(N'"?', N'?', '_') -- Returns __, I expected "_

SELECT REPLACE(N'-', N'?', '_') -- Returns -, I expected -
Run Code Online (Sandbox Code Playgroud)

另外,在LIKE例如中使用时很奇怪:

DECLARE @table TABLE ([Name] NVARCHAR(MAX))
INSERT INTO
    @table
VALUES
    ('John'),
    ('Jane')

SELECT
    *
FROM
    @table
WHERE
    [Name] LIKE N'%?%' -- This returns both records. I expected none.
Run Code Online (Sandbox Code Playgroud)

Sol*_*zky 8

当将夏威夷引号与字符串函数结合使用时,在T-SQL中有一些奇怪的行为。...其他角色也会遇到同样的问题吗?

一些东西:

  1. 这不是夏威夷语的“ quote”:它是一个会影响发音的“ glottal stop ”。
  2. 这不是“怪异”的行为:这不是您所期望的。
  3. 此行为不是特定的“问题”,尽管是的,还有其他一些字符也表现出相似的行为。例如,以下字符(上方的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
    
    Run Code Online (Sandbox Code Playgroud)

现在,任何使用SQL Server 2008或更高版本的人都应使用100(或更高)级别的排序规则。他们在100系列中增加了很多排序权重和大写/小写映射,而90系列,非编号系列或大多数过时的SQL Server排序规则(名称以开头的SQL_)都没有。

这里的问题不是它不等于任何其他字符(二进制排序规则之外),并且实际上它确实等于其他字符(U + 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      ?
*/
Run Code Online (Sandbox Code Playgroud)

问题在于,这是一个“间距修饰符”字符,因此,根据要处理的修饰符,它会附加到该字符之前或之后并对其含义/发音进行修改。

根据Unicode标准的第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'??aa' COLLATE Latin1_General_100_CI_AS, N'?',   N'_'); -- Returns ??aa
SELECT REPLACE(N'?aa'  COLLATE Latin1_General_100_CI_AS, N'?',   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
Run Code Online (Sandbox Code Playgroud)

如果您需要以忽略它们预期的语言行为的方式来处理此类字符,那么可以,您必须使用二进制排序规则。在这种情况下,请使用最新的排序规则级别,而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)

而且,有关归类/ Unicode /编码/等的更多信息,请访问:归类信息