为什么这些字符在SQL Server中都相等?


20

我就是不明白。请参阅以下SQL查询:

select nchar(65217) -- ﻁ
select nchar(65218) -- ﻂ
select nchar(65219) -- ﻃ
select nchar(65220) -- ﻄ
if nchar(65217) = nchar(65218)
    print 'equal'
if nchar(65217) = nchar(65219)
    print 'equal'
if nchar(65217) = nchar(65220)
    print 'equal'

基于传递关系,这意味着SQL Server会将它们全部视为相同的字符。

但是,在其他环境中(例如C#),它们是不同的。

我感到困惑的是:

  1. 字符串比较如何在SQL Server中工作
  2. 为什么比较在一台计算机和一个平台上的表现不一样,但是环境不同
  3. 这四个字符代表一个人类可理解的字符。为什么它们在Unicode字符图中如此丰富?

当然,这会导致巨大的问题,因为我正在处理文本处理应用程序,并且数据几乎来自任何地方,因此我需要在处理文本之前对其进行规范化。

如果我知道差异的原因,我可能会找到解决方案。谢谢。

Answers:


28

SQL Server中的所有字符数据都与一个排序规则相关联,该排序规则确定了可以存储的字符域以及用于比较和排序数据的规则。归类适用于Unicode和非Unicode数据。

SQL Server包括3大类归类:二进制,旧版和Windows。二进制类别(_BIN后缀)中的归类使用基础代码点进行比较,因此,如果代码点与字符无关,则相等比较返回不相等。传统(SQL_前缀)和Windows归类为更自然的字典规则提供了排序和比较语义。这样可以进行比较以考虑大小写,重音,宽度和假名。Windows归类提供了更健壮的word-sort规则,这些规则与Windows操作系统紧密匹配,而旧版归类仅考虑单个字符。

下面的示例说明Windows和使用Teth字符的二进制排序规则之间的区别:

CREATE TABLE dbo.WindowsColationExample
    (
      Character1 nchar(1) COLLATE Arabic_100_CI_AS_SC
    , Character2 nchar(1) COLLATE Arabic_100_CI_AS_SC
    , Character3 nchar(1) COLLATE Arabic_100_CI_AS_SC
    , Character4 nchar(1) COLLATE Arabic_100_CI_AS_SC
    );

CREATE TABLE dbo.BinaryColationExample
    (
      Character1 nchar(1) COLLATE Arabic_100_BIN
    , Character2 nchar(1) COLLATE Arabic_100_BIN
    , Character3 nchar(1) COLLATE Arabic_100_BIN
    , Character4 nchar(1) COLLATE Arabic_100_BIN
    );

INSERT  INTO dbo.BinaryColationExample
VALUES  ( NCHAR(65217), NCHAR(65218), NCHAR(65219), NCHAR(65220) );
INSERT  INTO dbo.WindowsColationExample
VALUES  ( NCHAR(65217), NCHAR(65218), NCHAR(65219), NCHAR(65220) );

--all characters compare not equal
SELECT *
FROM dbo.BinaryColationExample
WHERE
    character1 = character2
    OR character1 = character3
    OR character1 = character4
    OR character2 = character3
    OR character2 = character4
    OR character3 = character4;

--all characters compare equal
SELECT *
FROM dbo.WindowsColationExample
WHERE character1 = character2;
SELECT *
FROM dbo.WindowsColationExample
WHERE character1 = character3;
SELECT *
FROM dbo.WindowsColationExample
WHERE character1 = character4;
SELECT *
FROM dbo.WindowsColationExample
WHERE character2 = character3;
SELECT *
FROM dbo.WindowsColationExample
WHERE character2 = character4;
SELECT *
FROM dbo.WindowsColationExample
WHERE character3 = character4;

http://en.wikipedia.org/wiki/Duplicate_characters_in_Unicode中概述了为什么Unicode可能包含相同字形的不同代码点的原因 。我总结一下,这可能是为了实现旧兼容性,或者字符不是规范上相等的。请注意,Teth字符用于不同的语言(http://en.wikipedia.org/wiki/Teth)。


15

这与COLLATION您的数据库有关(BOL中的更多信息)。

我不能完全确定遇到问题的特定字符的语言(我猜是基于线程的波斯语),但是如果您在相等运算符中指定正确的排序规则,那么您可以获得准确的结果。

if nchar(65217) COLLATE Persian_100_BIN = nchar(65218) COLLATE Persian_100_BIN 
    print 'equal'; -- nothing returned
if nchar(65217)  COLLATE Persian_100_BIN  = nchar(65217)  COLLATE Persian_100_BIN 
    print 'equal'; -- prints 'equal'
if nchar(65217) COLLATE Latin1_General_CI_AI = nchar(65220) COLLATE Latin1_General_CI_AI
    print 'equal'; -- prints 'equal'
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.