在我编写的测试用例中,字符串比较似乎在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
为什么会有差异?
答案 0 :(得分:10)
Windows排序规则(例如Latin1_General_CI_AS
)使用Unicode类型排序规则。 SQL Collations没有。
这会导致连字符在两者之间区别对待。
答案 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)
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));