我有一个带有唯一键的表,其中包含一个NVARCHAR(50)
列(正确与否,但存在)。因此,当尝试插入Șc
或C
(插入的顺序无关紧要)时,由于排序规则问题,它会在第二个插入时中断。这是错误:
(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;
问题是旧的 SQL Server 排序规则(即
SQL_
那些名称80
以90
SQL Server 2005 附带)缺少大量字符的排序权重。100
从SQL Server 2008 附带的排序规则系列开始,这基本上得到了更正。正如您在下面的示例中看到的,
Ș
当使用非二进制、版本 80 或 90 排序规则(和 SQL Server 排序规则)时,该字符匹配一个空字符串,因为它们都具有相同的排序权重:0. Nothing。纳达。这意味着当N'Șc'
与N'C'
(使用前系列 100 排序规则)进行比较时,您实际上是N'c'
在与N'C'
(测试 #1)进行比较:因此,不幸的是,您将需要删除 PK,将列更改为具有 100 级排序规则(例如
Latin1_General_100_CI_AS_SC
),然后重新创建 PK。请注意,建议的排序规则与当前排序规则的区别在于末尾的和100
,_SC
这使其能够正确处理补充字符。这并不意味着您需要:
NVARCHAR
在 PK 中具有相同的设置)table.column = N'Ș'
,@variable = N'Ș'
因为变量和字符串文字使用数据库的默认排序规则。有关此行为的更多示例,请参阅我的以下博客文章的“补充字符”部分:
Uni-Code:搜索 T-SQL 标识符的有效字符的真实列表,第 3 部分,共 2 部分(定界标识符)