N'Șc'使用Latin1_General_CI_AS排序规则将N'C'的重复密钥视为


11

我有一个带有唯一键的表,该键包括一NVARCHAR(50)列(是否正确,但在那里)。因此,当尝试插入ȘcC(与插入顺序无关)时,由于排序规则问题,它在第二个插入处中断。这是错误:

(受影响的1行)消息2601,级别14,状态1,行16无法在具有唯一索引'IX_TestT'的对象'dbo.testT'中插入重复的键行。重复的键值为(C)。

选择返回:

在此处输入图片说明

数据库默认排序规则为Latin1_General_CI_AS。花了一些时间研究如何解决该问题,而又没有太大改变现有的结构,但是找不到找到工作的方法。尝试了不同的排序规则和组合,一切都失败了。阅读(此处此处)有关字符扩展等方面的信息,但仍然受阻。这是我用来复制问题的示例代码,可以随时进行修改并提出可以帮助解决此问题的任何建议。

CREATE TABLE testT (
    [Default_Collation]     [NVARCHAR] (50) COLLATE DATABASE_DEFAULT,
    [Latin1_General_CI_AS]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AS,
    [Latin1_General_CI_AI]  [NVARCHAR] (50) COLLATE Latin1_General_CI_AI,
    [SQL_Collation]         [NVARCHAR] (50) COLLATE SQL_Latin1_General_CP1_CI_AS);
CREATE UNIQUE CLUSTERED INDEX [IX_TestT] ON [dbo].[testT] ([Default_Collation])
ON [PRIMARY]
GO

INSERT INTO testT
SELECT  N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc',  --COLLATE Latin1_General_CI_AS
        N'Șc'   --COLLATE Latin1_General_CI_AS

INSERT INTO testT
SELECT  N'C'    --COLLATE Latin1_General_CI_AS 
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE Latin1_General_CI_AS
        ,N'C'   --COLLATE SQL_Latin1_General_CP1_CI_AS

SELECT * FROM testT;

DROP TABLE testT;

Answers:


10

问题是,旧的SQL Server排序规则(即那些开始的名字SQL_)和Windows排序规则的前两个版本(在80其附带的SQL Server 2000,并且没有在名称的版本号系列,以及90一系列SQL Server 2005附带)丢失了很多字符的排序权重。从100SQL Server 2008附带的系列排序规则开始,大多数情况已得到纠正。

从下面的示例中可以看到,Ș当使用非二进制版本80或90归类(和SQL Server归类)时,字符与空字符串匹配,因为它们的排序权重相同:0。无。娜达 这意味着,在N'Șc'N'C'(使用系列100预先排序)进行比较N'c'时,您实际上是与N'C'(测试1)进行比较:

SELECT 1 WHERE N'Șc' = N'C' COLLATE Latin1_General_CS_AS;
-- no result (due to "c" and "C" being different case)

SELECT 2 WHERE N'Ș' = N'' COLLATE SQL_Latin1_General_CP1_CI_AS;
SELECT 3 WHERE N'Ș' = N'' COLLATE Latin1_General_CI_AS;

SELECT 4 WHERE N'Ș' = N'' COLLATE Latin1_General_BIN2;
-- no result (due to "Ș" still being a code point and empty string has no code points)

SELECT 5 WHERE N'Ș' = N'' COLLATE Latin1_General_100_CI_AS;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

SELECT 6 WHERE N'Ș' = N'' COLLATE Chinese_PRC_CI_AI;
SELECT 7 WHERE N'Ș' = N'' COLLATE Chinese_PRC_90_CI_AI;

SELECT 8 WHERE N'Ș' = N'' COLLATE Indic_General_90_CI_AI;
SELECT 9 WHERE N'Ș' = N'' COLLATE Indic_General_100_CI_AI;
-- no result (due to "Ș" finally having a sort weight in 100 series Collations)

因此,不幸的是,您将需要删除PK,将列更改为具有100级归类(例如Latin1_General_100_CI_AS_SC),然后重新创建PK。请注意,建议的排序规则与当前排序规则的不同之处在于结尾处的100 _SC,这使其可以正确处理补充字符。

但这并不意味着你需要:

  1. 更改其他表的排序规则(除非它们NVARCHAR在PK中具有相同的设置)
  2. 更改数据库的默认排序规则。不更改数据库的归类的主要问题是,这样做table.column = N'Ș'和会存在行为差异,@variable = N'Ș'因为变量和字符串文字使用数据库的默认归类。

有关此行为的更多示例,请参见我的以下博客文章的“补充字符”部分:

统一代码:搜索T-SQL标识符的有效字符的真实列表,第2部分,共3部分(带分隔符的标识符)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.