使用 SC 排序规则的 SQL Server Unicode 查询

Posted

技术标签:

【中文标题】使用 SC 排序规则的 SQL Server Unicode 查询【英文标题】:SQL Server Unicode queries with SC Collation 【发布时间】:2015-09-21 17:24:17 【问题描述】:

在 SQL Server 2012 中,我有一个带有排序规则 Latin1_General_100_CI_AS_SC 的 nvarchar 列的表,它应该支持 unicode 代理对字符或补充字符。

    当我运行这个查询时:

    select KeyValue from terms where KeyValue = N'➰'
    

    (上面是 Unicode SC)上面是代码 10160 (x27B0) 的花环字符 结果是数百个看起来不同的单字符条目,即使它们都有不同的 UTF-16 代码点。这是因为整理吗?为什么没有完全匹配?编辑:我现在认为这是由于整理。 UTF-16 范围内似乎有一组“未定义”字符,超过 1733 个字符,并且通过这种排序规则将它们视为相同。虽然,代码高于 65535 的字符被视为唯一字符,并且这些查询返回完全匹配。

    以下两个查询有不同的结果:

    select KeyValue from terms where KeyValue = N'π'
    

    返回 3 行:π 和 ℼ 和 ᴨ

    select KeyValue from terms where KeyValue LIKE N'π'
    

    返回 2 行:π 和 ℼ 这是为什么呢?

    这是最奇怪的。这个查询:

    select KeyValue from terms where KeyValue like N'➰%'
    

    返回表中的几乎所有记录,其中包含许多多字符的常规拉丁字符集术语,例如“8w”或“apple”。 90% 未返回的都是以“æ”开头的。发生了什么?

注意:只是为了给这一点上下文,这些都是***的文章标题,而不是随机字符串。

【问题讨论】:

数据库排序规则是否支持 SC?它会影响查询中的字符串文字。 @RogerWolf 数据库的默认排序规则是相同的,如果这就是您的意思的话。 KeyValue是如何定义的? nvarchar(x),我猜?或varchar(x)? 非常有趣的问题。点赞。 这是一件奇怪的事情......您第一个查询中的字符是 CURLY LOOP (U+27B0)。此字符不应该需要代理对,因此“SC”排序规则应该是无关紧要的。我错过了什么吗? 【参考方案1】:

我有一个带有排序规则 Latin1_General_100_CI_AS_SC 的 nvarchar 列的表,它应该支持 Unicode 代理对字符或补充字符。

Supplementary Character-Aware (SCA) 排序规则——以_SC 或名称中以_140_ 结尾的排序规则——确实支持补充字符。但是,“支持”仅意味着内置函数将代理对作为单个补充代码点处理,而不是一对代理代码点。但对补充字符的排序和比较的支持实际上是从 SQL Server 2005 开始的,引入了 90 版排序规则。

即使它们都有不同的 UTF-16 代码点。这是因为整理吗?为什么没有完全匹配?

    UTF-16 没有码位,它是一种编码所有 Unicode 码位的编码。 是的,这种行为是由排序规则引起的。 没有完全匹配,因为(如您所料),代码点 U+27B0 没有定义的排序权重。因此它被完全忽略并等同于空字符串或任何其他没有排序权重的代码点。

UTF-16 范围内似乎有一组“未定义”字符,超过 1733 个字符,被此排序规则视为相同。

正确,但由于排序规则的重音敏感性,有些只有排序权重。如果你使用Latin1_General_100_CI_AI_SC,你会得到更多的匹配。而且,需要明确的是,UTF-16“范围”是所有 1,114,112 个 Unicode 代码点。

下面的两个查询结果不同……这是为什么呢?

我不能(还!)解释为什么 =LIKE 返回不同的匹配集,但还有 1 个字符等于您当前拥有的 3 个字符:

SELECT KeyValue, CONVERT(VARBINARY(40), [KeyValue])
FROM (VALUES (N'π' COLLATE Latin1_General_100_CI_AS_SC), (N'ℼ'), (N'ᴨ'),
             (N'Π')) t([KeyValue])
WHERE KeyValue = N'π'; -- 4 rows

SELECT KeyValue, CONVERT(VARBINARY(40), [KeyValue])
FROM (VALUES (N'π' COLLATE Latin1_General_100_CI_AS_SC), (N'ℼ'), (N'ᴨ'),
             (N'Π')) t([KeyValue])
WHERE KeyValue LIKE N'π'; -- 3 rows

这是最奇怪的。这个查询:...返回表中几乎所有的记录


SELECT 1 WHERE NCHAR(0x27B0) = NCHAR(0x0000) COLLATE Latin1_General_100_CI_AS_SC;
-- 1

SELECT 2 WHERE NCHAR(0x27B0) = N'' COLLATE Latin1_General_100_CI_AS_SC;
-- 2

SELECT 3 WHERE NCHAR(0x27B0) = NCHAR(0x27B0) + NCHAR(0x27B0) + NCHAR(0x27B0)
           COLLATE Latin1_General_100_CI_AS_SC;
-- 3

SELECT 4 WHERE N'➰' = N'➰   ➰    ➰    ➰' COLLATE Latin1_General_100_CI_AS_SC;
-- 4

SELECT 5 WHERE N'➰' LIKE N'➰   ➰    ➰    ➰' COLLATE Latin1_General_100_CI_AS_SC;
-- NO ROWS RETURNED!!  (spaces matter here due to LIKE)

SELECT 6 WHERE N'➰' LIKE N'➰➰➰➰➰➰' COLLATE Latin1_General_100_CI_AS_SC;
-- 6

这又与“➰”没有定义排序权重这一事实有关。当然,æÞßLJ 等也没有。

一旦我确切地弄清楚LIKE= 所做的不同之处,我将更新此答案。

更多信息,请参见:

How Many Bytes Per Character in SQL Server: a Completely Complete Guide Collations Info

【讨论】:

【参考方案2】:

SQL Server 和 tempdb 也有自己的排序规则,它们可能与数据库或列的排序规则不同。虽然应该为字符文字分配列或数据库的默认排序规则,但上述(可能过于简化)T-SQL 示例可能会错误陈述/没有揭示真正的问题。例如,为了简单起见,可以省略 ORDER BY 子句。当上述语句显式使用https://msdn.microsoft.com/en-us/library/ms184391.aspx ('COLLATE Latin1_General_100_CI_AS_SC') 时是否返回预期结果?

【讨论】:

以上是关于使用 SC 排序规则的 SQL Server Unicode 查询的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server转换数据库的排序规则

Sql Server - 使用排序规则

SQL Server 中索引的排序规则

SQL Server 2005 排序规则问题

如何选择 SQL Server 数据库的排序规则

SQL Server 不区分大小写的排序规则