字符串.NET和T-SQL之间的比较差异?

在我编写的测试用例中,字符串比较似乎在SQL Server / .NET CLR之间的工作方式不同。

这个C#代码:

string lesser = "SR2-A1-10-90"; string greater = "SR2-A1-100-10"; Debug.WriteLine(string.Compare("A","B")); Debug.WriteLine(string.Compare(lesser, greater)); 

将输出:

 -1 1 

这个SQL Server代码:

 declare @lesser varchar(20); declare @greater varchar(20); set @lesser = 'SR2-A1-10-90'; set @greater = 'SR2-A1-100-10'; IF @lesser < @greater SELECT 'Less Than'; ELSE SELECT 'Greater than'; 

将输出:

 Less Than 

为什么不同?

这在此处记录 。

Windows排序Latin1_General_CI_AS (例如Latin1_General_CI_AS )使用Unicode类型排序规则。 SQL Collat​​ions没有。

这会导致连字符在两者之间区别对待。

除了gbn的答案之外,您可以通过在C#中使用CompareOptions.StringSort(或使用StringComparison.Ordinal)使它们的行为相同。 这将符号视为在字母数字符号之前出现,因此“ – ”<“0”。

但是,Unicode与ASCII无法解释任何内容,因为ASCII代码页的hex代码逐字翻译为Unicode代码页:“ – ”是002D(45)而“0”是0030(48)。

发生的事情是.NET默认使用“语言”排序,它基于指定或当前文化应用于各种符号的非序数排序和权重。 例如,这种语言算法允许“简历”(带有重音拼写)在单词的排序列表中紧跟“简历”(拼写无重音符号)之后出现,因为“é”在“e”之后给出了小数顺序,远在“f”之前。 它还允许“合作”和“合作”紧密地放在一起,因为短划线符号具有较低的“重量”; 当排序诸如“位”,“位”和“位移”(这将按此顺序出现)之类的单词时,它仅作为绝对最终的断层连接器而言很重要。

所谓的序数排序(严格按照Unicode值,有或没有不区分大小写)会产生非常不同的,有时不合逻辑的结果,因为字母的变体通常在ASCII / Unicode序列中基本未修饰的拉丁字母后出现,而符号出现之前它。 例如,“é”出现在“z”之后,因此单词“resume”,“rosin”,“ruble”,“résumé”将按此顺序排序。 “比特”,“比特移位”,“比特”,“比特”将按照撇号首先按顺序排序,然后是短划线,然后是字母“e”,然后是字母“s”。 从“自然语言”的角度来看,这些都不符合逻辑。

  • 在SQL中你使用了varchar,它基本上是ASCII(需要整理),它会在0之前给出
  • 在C#中,所有字符串都是Unicode

UTF-xx(c#)与UCS-2(SQL Server)的细节非常棘手。

编辑:

我发布的太快了

我使用排序规则Latin1_General_CI_AS在SQL Server 2008上获得“大于”

编辑2:

我还会在破折号上尝试SELECT ASCII(...) 。 例如,如果SQL片段曾经存在于Word文档中 – (150)不是 – (45),我将其复制到SQL Server中,以便从您的问题中测试我的浏览器。 请参阅CP 1252 (= CP1 = SQL Server术语)

编辑3:请参阅Martin Smith的答案:2个排序规则具有不同的排序顺序。

几个很好的答案已经解释了为什么会发生这种情况,但我确信其他人只是想知道C#代码以与SQL服务器相同的顺序迭代集合。 我发现以下效果最好。 “Ordinal”绕过连字符问题,而“IgnoreCase”似乎也反映了SQL服务器的默认值。

 Debug.WriteLine(string.Compare(lesser, greater, StringComparison.OrdinalIgnoreCase));