选择二进制排序规则,可以区分Sql Server中nvarchar列的'ss'和'ß'

Say*_*Pal 11 t-sql sql-server unicode collation sql-server-2016

作为默认的SQL_Latin1_General_CP1_CI_ASSQL服务器的排序规则不能区分ssß,我想换一个特定列的排序规则在表中SQL_Latin1_General_CP437_BIN2,如建议在这里.

但是,我不确定这是否通常是一种好的做法.此外,我不确定除以下之外的其他影响:

  • 更改排序顺序:由于我从不对此列上的数据进行排序,因此对我来说可能不是问题.但是,如果您不这么认为,请告诉我.
  • 不区分大小写区分大小写敏感:由于我的应用程序始终以小写形式提供文本,我认为这种改变对我来说也不会成为问题.但是,如果您不这么认为,请告诉我.

我很好奇这个变化的其他主要影响,如果有的话.

此外,我还想知道以下哪一个最适合这种情况:

SQL_Latin1_General_CP437_BIN

描述: Latin1-常规,Unicode数据的二进制排序,SQL Server在代码页437上的排序顺序30用于非Unicode数据


SQL_Latin1_General_CP437_BIN2

描述: Latin1-常规,Unicode数据的二进制代码点比较排序,SQL Server在代码页437上的排序顺序30用于非Unicode数据


SQL_Latin1_General_CP850_BIN

描述: Latin1-常规,Unicode数据的二进制排序,SQL Server在代码页850上的排序顺序40,用于非Unicode数据


SQL_Latin1_General_CP850_BIN2

描述: Latin1-常规,Unicode数据的二进制代码点比较排序,SQL Server在代码页850上的排序顺序40,用于非Unicode数据

如果您认为其他排序规则更适合此方案,请同时提及这些排序规则.


2017年3月19日更新: 对于提出此问题的任何人:

  • 必须检查@srutzky和@SqlZim的答案,以及相关的引用资源.在这种情况下,你不想急于做事.
  • 由于更改排序规则不适合胆小鬼:P,保留表数据的备份可能会派上用场.
  • 还要检查列的依赖关系,例如索引和约束; 你可能需要删除并创建那些,就像我的情况一样.

玩得开心 :)

Sol*_*zky 16

关于Collat​​ions的一些事情:

  1. SQL_SQL Server 2000开始,Collat​​ions被弃用(是的,2000).如果你可以避免使用它们,你应该(但这并不意味着如果没有迫切需要改变一堆东西!).

    SQL_Collat​​ions 的问题实际上只与VARCHAR(即非Unicode)数据有关,因为NVARCHAR(即Unicode)数据使用OS中的规则.但VARCHAR遗憾的是,排序和比较数据的规则使用了简单的映射,并没有包含更复杂的语言规则.这就是为什么ss并且ßVARCHAR使用相同的SQL_Latin1_General_CP1_CI_ASCollat​​ion 存储时不等同.当在单词的中间使用时,这些已弃用的Collat​​ions也无法给破折号赋予较低的权重.非SQL_Collat​​ions(即Windows Collat​​ions)对两者使用相同的规则VARCHAR,NVARCHAR因此VARCHAR处理更加健壮,更加一致NVARCHAR.

  2. _BINSQL Server 2005开始,Collat​​ions已被弃用.如果你可以避免使用它们,你应该(但这并不意味着如果没有迫切需要改变一堆东西!).

    _BINCollat​​ions 的问题相当微妙,因为它只影响排序.由于它们在字节级别进行比较(因此没有语言规则),因此在Collat​​ions _BIN_BIN2Collat​​ions 之间进行比较是相同的.但是,由于SQL Server(和Windows/PC)是Little Endian,实体以反向字节顺序存储.这在处理双字节"字符"时变得明显,这就是NVARCHAR数据:UTF-16 Little Endian.这意味着Unicode代码点U + 1216在Big Endian系统上具有0x1216的十六进制/二进制表示,但在Little Endian系统上存储为0x1612.要完整循环,以便最后一点的重要性(希望)变得明显:_BINCollat​​ions将逐字节比较(在第一个字符之后),因此将U + 1216视为0x16然后是0x12,而_BIN2Collat​​ions将比较代码点代码点,因此将U + 1216视为0x12然后是0x16.

  3. 这种特殊的列NVARCHAR(一个VARCHAR使用列SQL_Latin1_General_CP1_CI_AS不等同于ssß)等单独仅此列,也没有什么区别SQL_Latin1_General_CP437_BIN2,并SQL_Latin1_General_CP850_BIN2为Unicode是一个单一的,包罗万象的字符集所致.

  4. 对于VARCHAR数据,会有区别,因为它们是不同的代码页(437850),并且它们都不同于您现在使用的CP1代码页(==代码页1252).

  5. 虽然使用二进制排序往往是矫枉过正,在这种情况下,它可能会因为只有一个区域/文化并不等于必须ßss匈牙利.使用匈牙利语校对可能有一些你不想要的语言规则(或者至少不会期望),所以二进制校对在这里似乎是更好的选择(不是你要问的4个中的任何一个:-) .请记住,通过使用二进制排序规则,您不仅放弃所有语言规则,而且还失去了将同一字符的不同版本等同起来的能力,例如A(Latin Capital Letter A U + 0041)和?(Fullwidth)拉丁大写字母A U + FF21).

    使用以下查询来查看哪些排序规则是非二进制的,并且不等于这些字符:

    DECLARE @SQL NVARCHAR(MAX) = N'DECLARE @Counter INT = 1;';
    
    SELECT @SQL += REPLACE(N'
      IF(N''ß'' COLLATE {Name} <> N''ss'' COLLATE {Name})
      BEGIN
        RAISERROR(N''%4d.  {Name}'', 10, 1, @Counter) WITH NOWAIT;
        SET @Counter += 1;
      END;
    ', N'{Name}', col.[name]) + NCHAR(13) + NCHAR(10)
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] NOT LIKE N'SQL[_]%'
    AND    col.[name] NOT LIKE N'%[_]BIN%'
    ORDER BY col.[name]
    
    --PRINT @SQL;
    EXEC (@SQL);
    
    Run Code Online (Sandbox Code Playgroud)

所以:

  • 如果您打算使用二进制排序规则,请使用类似的方法Latin1_General_100_BIN2.
  • 不是要改变整个数据库的整理和所有的表.这是很多工作,唯一的"内置"机制是无证的(即不受支持).
  • 如果要更改数据库的默认排序规则,则会影响数据库范围的项目(如表,列,索引,函数,存储过程等)的名称解析.含义:您需要回归100%接触数据库的应用程序,以及触摸此数据库的所有SQL Server代理作业等.
  • 如果大多数/所有使用此列需要查询ßss被看作是不同的,然后继续前进,改变使用的列Latin1_General_100_BIN2.这可能需要删除以下依赖对象,然后在以下后重新创建ALTER TABLE:

    • 索引
    • 独特的约束
    • 外键约束

    提示:确保检查列的当前NULL/NOT NULL设置,并在ALTER TABLE ... ALTER COLUMN ...语句中指定它以使其不会更改.

  • 如果只有一些查询需要这种不同的行为,那么COLLATE在每个条件的基础上(例如WHERE tab.[ThisColumn] LIKE N'%ss%' COLLATE Latin1_General_100_BIN2)覆盖那些与子句的比较操作.该COLLATE只需要一方(的运营商)关键字作为排序规则的优先将其应用到另一边.

有关使用字符串和排序规则的更多信息,请访问:排序规则信息

  • 谢谢你的详细回答:) (2认同)
  • 非常详尽,再次感谢您对请求的答复! (2认同)

Sql*_*Zim 6

通常,BIN2优先于BIN,并且您可能希望在sql排序规则上选择Windows排序规则.例如Latin1_General_100_BIN2

使用BIN和BIN2排序规则

使用BIN排序规则

如果SQL Server应用程序与使用二进制排序规则的旧版SQL Server交互,请继续使用二进制文件.对于混合环境,二进制排序可能是更合适的选择.


出于类似的原因是什么刚被有关规定BIN2排序规则,除非你有特殊要求,以保持向后兼容性问题,您应该倾斜向使用Windows排序规则,并开始与SQL不是SQL Server特定的归类(即那些有现在被认为有点"sucky";-)).
- 更改数据库默认排序规则时@srutzky - Latin1_General_BIN性能影响


rextester演示:http://rextester.com/KIIDYH74471

create table t (
    a varchar(16)  --collate SQL_Latin1_General_CP1_CI_AS /* default */
  , b varchar(16)  --collate SQL_Latin1_General_CP1_CI_AS
  , c nvarchar(16) --collate SQL_Latin1_General_CP1_CI_AS
  , d nvarchar(16) --collate SQL_Latin1_General_CP1_CI_AS 
);
insert into t values ('ss','ß',N'ss',N'ß');
select *
    , case when a = b then '=' else '!=' end as [a=b] /* != */
    , case when a = d then '=' else '!=' end as [a=d] /* = */
    , case when c = b then '=' else '!=' end as [c=b] /* = */
    , case when c = d then '=' else '!=' end as [c=d] /* = */
from t;
Run Code Online (Sandbox Code Playgroud)

收益:

+----+---+----+---+-----+-----+-----+-----+
| a  | b | c  | d | a=b | a=d | c=b | c=d |
+----+---+----+---+-----+-----+-----+-----+
| ss | ß | ss | ß | !=  | =   | =   | =   |
+----+---+----+---+-----+-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)
create table t (
    a varchar(16)  collate Latin1_General_100_BIN2
  , b varchar(16)  collate Latin1_General_100_BIN2
  , c nvarchar(16) collate Latin1_General_100_BIN2
  , d nvarchar(16) collate Latin1_General_100_BIN2
);
insert into t values ('ss','ß',N'ss',N'ß');
select *
    , case when a = b then '=' else '!=' end as [a=b] /* != */
    , case when a = d then '=' else '!=' end as [a=d] /* != */
    , case when c = b then '=' else '!=' end as [c=b] /* != */
    , case when c = d then '=' else '!=' end as [c=d] /* != */
from t;
Run Code Online (Sandbox Code Playgroud)

收益:

+----+---+----+---+-----+-----+-----+-----+
| a  | b | c  | d | a=b | a=d | c=b | c=d |
+----+---+----+---+-----+-----+-----+-----+
| ss | ß | ss | ß | !=  | !=  | !=  | !=  |
+----+---+----+---+-----+-----+-----+-----+
Run Code Online (Sandbox Code Playgroud)

  • @SayanPal 我不得不说这取决于,但我会看看我是否可以让 srutzky 提供一些建议。 (2认同)