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

时间:2010-09-27 21:46:10

标签: c# sql sql-server string comparison

在我编写的测试用例中,字符串比较似乎在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

为什么会有差异?

4 个答案:

答案 0 :(得分:10)

这是documented here

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

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

答案 1 :(得分:7)

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

但是,Unicode与ASCII没有任何解释,因为ASCII代码页的十六进制代码被逐字翻译成Unicode代码页:“ - ”是002D(45)而“0”是0030(48)。

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

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

答案 2 :(得分:3)

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

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

编辑:

我发布的太快了

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

编辑2:

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

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

答案 3 :(得分:0)

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

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