【问题标题】:How to find out whether collation uses word sort or string sort?如何找出排序规则是使用单词排序还是字符串排序?
【发布时间】:2015-11-19 11:03:27
【问题描述】:

https://stackoverflow.com/a/361059/14731 讨论“单词排序”和“字符串排序”的区别。

当 SQL 排序规则将使用“单词排序”与“字符串排序”时,如何以编程方式进行查询?

推论:是否所有排序规则都对 Unicode 字符串使用“单词排序”,对非 Unicode 字符串使用“字符串排序”?

SELECT * from sys.fn_HelpCollations()
WHERE name = 'SQL_Latin1_General_CP1_CI_AS'

提供了很多关于排序规则的细节,但请注意它没有提到“单词排序”。

【问题讨论】:

    标签: sql-server sorting unicode collation


    【解决方案1】:

    让我们从 Microsoft 给出的这些类型的定义开始(摘自CompareOptions Enumeration MSDN 页面的“备注”部分):

    .NET Framework 使用三种不同的排序方式:单词排序、字符串排序和序数排序。 Word 排序对字符串执行区分区域性的比较。某些非字母数字字符可能具有分配给它们的特殊权重。例如,连字符(“-”)可能分配给它的权重非常小,因此“coop”和“co-op”在排序列表中彼此相邻出现。字符串排序类似于单词排序,只是没有特殊情况。因此,所有非字母数字符号都位于所有字母数字字符之前。序数排序根据字符串中每个元素的 Unicode 值比较字符串。

    Unicode 具有文化敏感性和权重,XMLN 前缀类型是 Unicode,因此他们可能会说 Unicode 类型中的数据使用“字排序”,而非 Unicode 类型中的数据使用“字符串排序”。 Ordinal 指的是BINBIN2 排序规则,尽管BIN 排序规则不是100% 的排序规则,因为它们处理第一个字符的方式。

    但是让我们看看 SQL Server 说它在做什么。运行以下命令:

    DECLARE @SampleData TABLE (ANSI VARCHAR(50), UTF16 NVARCHAR(50));
    INSERT INTO @SampleData (ANSI, UTF16) VALUES 
        ('a-b-c', N'a-b-c'),
        ('ac', N'ac'),
        ('aba', N'aba'),
        ('a-b', N'a-b'),
        ('ab', N'ab');
    
    SELECT sd.ANSI AS [ANSI-Latin1_General_100_CI_AS]
    FROM   @SampleData sd
    ORDER BY sd.ANSI COLLATE Latin1_General_100_CI_AS ASC;
    
    SELECT sd.UTF16 AS [UTF16-Latin1_General_100_CI_AS]
    FROM   @SampleData sd
    ORDER BY sd.UTF16 COLLATE Latin1_General_100_CI_AS ASC;
    
    SELECT sd.ANSI AS [ANSI-SQL_Latin1_General_CP1_CI_AS]
    FROM   @SampleData sd
    ORDER BY sd.ANSI COLLATE SQL_Latin1_General_CP1_CI_AS ASC;
    
    SELECT sd.UTF16 AS [UTF16-SQL_Latin1_General_CP1_CI_AS]
    FROM   @SampleData sd
    ORDER BY sd.UTF16 COLLATE SQL_Latin1_General_CP1_CI_AS ASC;
    

    结果:

    ANSI-Latin1_General_100_CI_AS
    -------------------------------------
    ab
    a-b
    aba
    a-b-c
    ac
    
    UTF16-Latin1_General_100_CI_AS
    -------------------------------------
    ab
    a-b
    aba
    a-b-c
    ac
    
    ANSI-SQL_Latin1_General_CP1_CI_AS
    -------------------------------------
    a-b
    a-b-c
    ab
    aba
    ac
    
    UTF16-SQL_Latin1_General_CP1_CI_AS
    -------------------------------------
    ab
    a-b
    aba
    a-b-c
    ac
    

    嗯。只有 SQL_ 排序规则与 VARCHAR 字段组合似乎正在执行可以被视为“字符串排序”的操作。 SQL_ 排序规则与NVARCHAR 字段组合将执行“单词排序”,这是与非SQL_ 排序规则相同的Unicode 处理。但是除了确定“字符串”与“单词”排序的 SQL Server 排序规则(即以 SQL_ 开头)之外,还有其他东西吗?让我们看看我们可以提取的排序规则的唯一属性:

    SELECT N'Latin1_General_100_CI_AS' AS [CollationName],
           COLLATIONPROPERTY('Latin1_General_100_CI_AS', 'CodePage') AS [CodePage],
           COLLATIONPROPERTY('Latin1_General_100_CI_AS', 'LCID') AS [LCID],
          COLLATIONPROPERTY('Latin1_General_100_CI_AS', 'ComparisonStyle') AS [ComparisonStyle]
    UNION ALL
    SELECT N'SQL_Latin1_General_CP1_CI_AS' AS [CollationName],
           COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'CodePage'),
           COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'LCID'),
           COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS', 'ComparisonStyle');
    

    结果:

    CollationName                  CodePage   LCID    ComparisonStyle
    ----------------------------   --------   ----    ---------------
    Latin1_General_100_CI_AS       1252       1033    196609
    SQL_Latin1_General_CP1_CI_AS   1252       1033    196609
    

    因此,那里没有明显的差异。这似乎给我们留下了这个:

    字符串排序在以下情况下完成:

    • 排序规则名称以SQL_ 开头,AND
    • 数据(字段、变量、字符串文字)是非 Unicode(即 CHAR / VARCHAR / TEXT)

    有关一般 Unicode 排序的更多信息,请查看以下资源:

    【讨论】:

    • 感谢您的详细回答,但不幸的是这还不够。虽然unicode.org/reports/tr10 提到“可忽略的字符”,但我不知道在哪里查找每个排序规则的可忽略字符列表。例如,当SQL_Latin1_General_CP1_CI_AS 处于 unicode 模式时,连字符应该是可以忽略的。每个排序规则没有此类信息的查找表吗?
    • @Gili 我刚刚回答了您的相关问题,它可能包含其他详细信息,可以为您的后续问题提供洞察力。对于任何 Unicode(这与 SQL_Latin1_General_CP1_CI_AS 无关,它与使用 NVARCHAR / NCHAR / XML 有关)排序,排序规则是应用了任何特定于语言环境的规则的 UCA 算法。我不知道有什么方法可以“发现”如何处理一个字符,因为算法会考虑上下文(即周围的字符)。
    • @Gili 另外,请转到我的答案中的 Collat​​ion Charts 链接。然后单击左侧导航顶部的“帮助”链接。这将描述权重的多个级别。然后在左侧导航中,您将看到“标点符号”的链接(向下第 4 个)。这会让你更接近吗?
    • 并非如此。我会尝试改写... UCA算法讨论了不同的比较级别。第 3 级处理区分大小写。第 4 级处理可忽略的标点符号。它在哪里说SQL_Latin1_General_CP1_CI_AS 映射到比较级别 3(忽略标点符号)?你是说我应该假设 all unicode 比较使用级别 3?
    • 优秀的侦探作品!我接受了你的回答。
    【解决方案2】:
    • srutzky's 出色的答案表明,除了由 SQL_ 整理器处理的非 Unicode 类型外,所有其他数据均根据“Unicode 整理”规则进行排序。
    • 令人困惑的是,Microsoft 不使用 Unicode 标准的排序规则。
    • 根据https://support.microsoft.com/en-us/kb/322112

      SQL Server 2000 支持两种排序规则:

      • SQL 排序规则
      • Windows 排序规则

      [...]

      对于 Windows 排序规则,非 Unicode 数据的比较是通过使用与 Unicode 数据相同的算法来实现的。

      [...]

      用于排序非 Unicode 数据的 SQL 排序规则与 Microsoft Windows 操作系统提供的任何排序例程都不兼容;但是,Unicode 数据的排序与特定版本的 Windows 排序规则兼容。

    • 我将其解释为:

      • SQL_ 排序规则是“SQL 排序规则”
      • 所有其他整理者都是“Windows整理者”。
      • SQL_ 整理器处理的非Unicode 类型外,所有其他数据均根据“Windows 整理”进行排序。

    那么,让我们深入研究“Windows 排序规则”。

    //  Sorting Flags.
    //
    //    WORD Sort:    culturally correct sort
    //                  hyphen and apostrophe are special cased
    //                  example: “coop” and “co-op” will sort together in a list
    //
    //                        co_op     <——-  underscore (symbol)
    //                        coat
    //                        comb
    //                        coop
    //                        co-op     <——-  hyphen (punctuation)
    //                        cork
    //                        went
    //                        were
    //                        we’re     <——-  apostrophe (punctuation)
    //
    //
    //    STRING Sort:  hyphen and apostrophe will sort with all other symbols
    //
    //                        co-op     <——-  hyphen (punctuation)
    //                        co_op     <——-  underscore (symbol)
    //                        coat
    //                        comb
    //                        coop
    //                        cork
    //                        we’re     <——-  apostrophe (punctuation)
    //                        went
    //                        were
    

    【讨论】:

    • 你好。一些笔记。 1) “微软不使用 Unicode 标准的排序规则。”这并不完全正确,或者至少它的陈述过于宽泛。 Microsoft 实现了 Windows 和 SQL 排序规则。之所以使用 SQL 排序规则,是因为当时 SQL Server 无法使用 Windows 排序规则。但是对于 Unicode 数据(即存储在 XML 或 N 前缀类型中的任何内容),它们肯定会使用 Unicode 排序规则。请记住,在 Unicode.org 上找到的规则变化比在实施其建议的软件包中反映的要频繁。
    • (续)2) "SQL Server 2000 支持两种排序规则:" SQL Server 2000 现在有 6 个旧版本。您应该使用当前文档进行验证。然而,幸运的是,这些信息仍然是真实的。 3) 您的三点解释是正确的,尽管只是重申了我的答案中的内容以及您在此答案顶部所说的内容(除非您将“Unicode”这个词换成了“Windows”)。
    • (续)4) “对于 Unicode 数据类型,数据比较基于 Unicode 代码点。”这句话完全断章取义,因此本身就是不正确的。发表该声明时正在讨论的主题是“二进制排序规则”。他们说二进制排序规则根据 Unicode 代码点对 Unicode 数据进行排序,如果查看区域设置的非 Unicode 代码页,相同字符的顺序可能不同。但是,该段的前两句话解释了非二进制排序规则如何处理排序,这与我的回答一致。
    • (cont.) 5) 最后两项——winnls.h 中引用的部分和“在您的应用程序中处理排序”——似乎与我引用并给出了示例代码。唯一的区别似乎是他们明确指定“连字符和撇号”作为特殊情况。如果这是我的答案中唯一缺少的项目,并且它是重要项目,那么我可以轻松添加它,尽管它不是原始问题的一部分。但如果它有助于澄清,作为底部的注释会很好。
    • @srutzky 你如何解释_ 排在# 之前的事实?这似乎与stackoverflow.com/a/32706275/14731 中提到的 Unicode 排序顺序不匹配。在我自己的实验中,排序顺序似乎对应于 Unicode 代码点比较以及标点符号的特殊处理。意思是,它们看起来不像使用普通的 Unicode 排序算法。
    猜你喜欢
    • 2013-06-12
    • 2020-03-02
    • 2012-09-11
    • 2015-10-09
    • 2011-05-27
    • 2013-09-26
    • 2013-02-08
    • 2012-01-19
    • 2023-01-18
    相关资源
    最近更新 更多