nvarchar 类型的不区分大小写的主键,其中 ß != ss

Posted

技术标签:

【中文标题】nvarchar 类型的不区分大小写的主键,其中 ß != ss【英文标题】:Case-insensitive primary key of type nvarchar where ß != ss 【发布时间】:2015-01-22 06:47:51 【问题描述】:

这个问题“Need a case insensitive collation where ss != ß”解决了varchar类型的列,但我的必须是nvarchar

据我所知,SQL_Latin1_General_Cp437_BIN 区分 ßss。但它也区分大小写。我的是一个主键列,它也需要不区分大小写:

我需要例如weiß/Weiß 被认为是相等的,还有weiss/Weiss,但不是weiß/weiss 也不是Weiß/Weiss 也不是weiß/@987654336 等。 /p>

我已经为此进行了很多搜索,难道真的让我在这里不走运吗?肯定有很多人处于同样的境地,我简直不敢相信这是无法解决的。

【问题讨论】:

您知道德语规则与您的要求相矛盾吗? @TomTom 至于语言规则,我不太确定,但无论如何这与问题无关。 你的理由无关紧要。 SQL Server 不支持您制定的规则并且不支持自定义排序规则。这意味着您的问题没有简单的解决方案。您基本上可以致电 MS 并要求他们执行您的规则。这与 liunquistic 无关——您可能有正当理由。但由于 SQL Server 仅支持官方规则,因此您制定的规则不会让您没有单一的排序规则匹配。无论是谁设计的,都确保他在象牙塔中设计它,而忽略了所涉及系统的限制。 复杂。基本上以遵循您的规则的方式制作您自己的正确字符串。需要时将 ß 重新编码为 ss 等,然后使用二进制排序规则。它会很脏,但这是唯一的方法。 @TomTom 实际上有一个排序规则,所以 SQL Serer 确实支持它,它是“官方的”,而不是大卫的“制定规则”。有几个可以工作,都是Hungarian_Technical 的子集。详情请看我的回答。 【参考方案1】:

啊,但它可能的,因为一个自然地处理这个的排序规则(实际上有几个,但都在同一个“家族”中):Hungarian_Technical_ *(嗯,减去区分大小写 (CS) 和二进制 (BIN / BIN2) 的变体)。当然,我仍然不确定这是一个PK的好选择,但没有理由不能是UNIQUE INDEX

SELECT tmp.*,
       IIF(tmp.[First] = tmp.[Second] COLLATE Hungarian_Technical_CI_AI,
           N'Equal',
           N'NOT EQUAL') AS [Result]
FROM (
      SELECT N'weiß', N'Weiß', N'Equal'
      UNION ALL
      SELECT N'weiss', N'Weiss', N'Equal'
      UNION ALL
      SELECT N'weiß', N'weiss', N'NOT Equal'
      UNION ALL
      SELECT N'Weiß', N'Weiss', N'NOT Equal'
      UNION ALL
      SELECT N'weiß', N'Weiss', N'NOT Equal'
      ) tmp ([First], [Second], [Ideal]);

结果:

First   Second  Ideal       Result
weiß    Weiß    Equal       Equal
weiss   Weiss   Equal       Equal
weiß    weiss   NOT Equal   NOT EQUAL
Weiß    Weiss   NOT Equal   NOT EQUAL
weiß    Weiss   NOT Equal   NOT EQUAL

总共有 24 个排序规则将以这种方式工作。您可以通过以下方式找到它们:

SELECT hc.*
FROM sys.fn_HelpCollations() hc
WHERE hc.name LIKE N'Hungarian[_]Technical%'
AND hc.name LIKE N'%[_]CI%'
ORDER BY hc.name;

他们是:

Hungarian_Technical_100_CI_AI Hungarian_Technical_100_CI_AI_KS Hungarian_Technical_100_CI_AI_KS_SC Hungarian_Technical_100_CI_AI_KS_WS 匈牙利语_Technical_100_CI_AI_KS_WS_SC Hungarian_Technical_100_CI_AI_SC Hungarian_Technical_100_CI_AI_WS 匈牙利语_Technical_100_CI_AI_WS_SC 匈牙利语_Technical_100_CI_AS 匈牙利语_Technical_100_CI_AS_KS 匈牙利语_Technical_100_CI_AS_KS_SC Hungarian_Technical_100_CI_AS_KS_WS 匈牙利语_Technical_100_CI_AS_KS_WS_SC Hungarian_Technical_100_CI_AS_SC Hungarian_Technical_100_CI_AS_WS 匈牙利语_技术_100_CI_AS_WS_SC 匈牙利语_技术_CI_AI 匈牙利语_技术_CI_AI_KS 匈牙利语_技术_CI_AI_KS_WS 匈牙利语_技术_CI_AI_WS 匈牙利语_技术_CI_AS 匈牙利语_技术_CI_AS_KS 匈牙利语_技术_CI_AS_KS_WS 匈牙利语_技术_CI_AS_WS

如果版本 100 排序规则可用(意味着:您使用的是 SQL Server 2008 或更高版本),则使用这些排序规则,而不是名称中没有版本号的排序规则。

编辑: 我发现了一些可能感兴趣的关于“匈牙利技术”排序规则的附加信息:

mysql: Hungarian collation -- 这是一些 MySQL 开发人员试图弄清楚如何实现排序规则的细节的 listserv 讨论的存档。显然它有一些复杂的规则,至少部分是由于需要将多个字符等同为一个字符进行排序(查找“3.特殊的二合字母/三合字母规则”部分)。这可能会导致一些意外行为。该部分中注明了特定的字母组合,因此至少可以更轻松地设置测试用例来帮助确定排序规则是否使用此排序规则无效。

Why are there so many(106) Hungarian collations? -- 这是关于 social.msdn 的讨论,其中包含一些有趣的信息。 Erland Sommarsko 在其中有一条评论,他在其中指出:

我运行了一个疯狂的性能测试来测试 SQL 2008 中的所有排序规则。我有一个空闲的服务器可用,测试运行了 8-9 天。我记得 Hungarian_Technical 是最慢的。

鉴于 MySQL 开发人员对复杂规则的讨论,这些测试结果似乎并不那么令人惊讶。

因此,在决定是否采用简单的方法将 NVARCHAR 字段设置为这些 Hungarian Technical 排序规则之一,或者采用 @GarethD 对计算列的建议时,可能应该将这两项考虑在内。

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

【讨论】:

非常有趣!我明天也会测试这个。虽然它在 weiß 的情况下有效,但我想知道是否还有其他关于 hangarian_technical_* 的怪癖会以意想不到的方式等同于其他事物..【参考方案2】:

我能找到的最接近解决方法的方法是使用索引视图在 UPPER(ID) 上添加唯一约束,以阻止实际主键上使用的二进制排序规则未发现的主键违规,例如

CREATE TABLE CollationTest 
(
        ID NVARCHAR(50) COLLATE Latin1_General_BIN NOT NULL,
    CONSTRAINT PK_CollationTest_ID PRIMARY KEY (ID)
);
GO
CREATE VIEW dbo.CollationTestConstraint
WITH SCHEMABINDING
AS
    SELECT  ID = UPPER(ID)
    FROM    dbo.CollationTest;
GO
CREATE UNIQUE CLUSTERED INDEX UQ_CollationTestConstraint_ID 
    ON dbo.CollationTestConstraint (ID);

现在以下内容将作为初始插入:

INSERT dbo.CollationTest (ID) VALUES ('weiß');
INSERT dbo.CollationTest (ID) VALUES ('Weiss');

但以下会失败:

INSERT dbo.CollationTest (ID) VALUES ('Weiß');
INSERT dbo.CollationTest (ID) VALUES ('weiss');

无法在具有唯一索引“UQ_Collat​​ionTestConstraint_ID”的对象“dbo.Collat​​ionTestConstraint”中插入重复的键行。重复键值为 (WEIß)。

无法在具有唯一索引“UQ_Collat​​ionTestConstraint_ID”的对象“dbo.Collat​​ionTestConstraint”中插入重复的键行。重复键值为 (WEISS)。

经过初步测试,这似乎符合您的标准。

编辑

我确实过于复杂了,您可以使用计算列和唯一约束来实现相同的目标:

CREATE TABLE CollationTest 
(
        ID NVARCHAR(50) COLLATE Latin1_General_BIN NOT NULL,
        IDUpper AS UPPER(ID),
    CONSTRAINT PK_CollationTest_ID PRIMARY KEY (ID),
    CONSTRAINT UQ_CollationTest_IDUpper UNIQUE (IDUpper)
);

【讨论】:

以上是关于nvarchar 类型的不区分大小写的主键,其中 ß != ss的主要内容,如果未能解决你的问题,请参考以下文章

在主键的情况下哪个更好 bigint 或 nvarchar

MySQL 对主键区分大小写

接受所有数据类型的不区分大小写的 C++ 排序?

在 C# 中具有字符串键类型的不区分大小写字典

简单SQL语句

区分关系行数据库的主表和从表