C# LINQ与Oracle中OrderBy对含点字符串排序差异的原因问询
问题背景
先看你给出的两个场景:
Oracle 查询及结果
select * from ( select 'LM.CHARLET' c from dual union select 'L.MOURLIN' c from dual union select 'Y.LEFEUVRE' c from dual union select 'S.MIRO' c from dual ) order by c
返回结果:
LM.CHARLET L.MOURLIN S.MIRO Y.LEFEUVRE
C# 代码及结果
List<string> testLst = new List<string> { "LM.CHARLET", "L.MOURLIN", "Y.LEFEUVRE", "S.MIRO" }; List<string> orderedLst = testLst.OrderBy(p => p).ToList();
返回结果:
L.MOURLIN LM.CHARLET S.MIRO Y.LEFEUVRE
为什么排序结果不一样?
核心原因很直白:Oracle和C#默认使用的字符排序规则(Collation)完全不同,两者对字符串中点号.这类标点符号的处理逻辑有本质区别。
1. Oracle的默认排序逻辑
Oracle的排序行为由数据库的NLS_SORT和NLS_COMP参数控制,默认情况下,大多数Oracle环境会采用忽略非字母数字符号的排序规则。也就是说,比较字符串时,点号会被直接跳过,只对比字母部分:
- 拿
LM.CHARLET和L.MOURLIN来说,相当于对比LMCHARLET和LMOURLIN - 前两个字符都是
L和M,第三个字符C的顺序在O之前,所以LM.CHARLET会排在L.MOURLIN前面。
2. C#的默认排序逻辑
C#里OrderBy默认使用当前线程文化(比如系统默认语言区域)对应的排序规则,这种规则会把标点符号当作普通字符参与排序。点号.的ASCII码是46,字母M的ASCII码是77,.的优先级比M低:
- 对比
L.MOURLIN和LM.CHARLET时,第三个字符分别是.和M,.更小,所以L.MOURLIN会排在LM.CHARLET前面。
如何让两边排序结果一致?
如果需要两边排序结果对齐,可以手动指定统一的排序规则:
让Oracle和C#默认结果一致
在Oracle中使用二进制排序(严格按ASCII码比较,和C#默认逻辑对齐):
select * from ( select 'LM.CHARLET' c from dual union select 'L.MOURLIN' c from dual union select 'Y.LEFEUVRE' c from dual union select 'S.MIRO' c from dual ) order by NLSSORT(c, 'NLS_SORT=BINARY');
让C#和Oracle默认结果一致
在C#中指定忽略符号的排序规则:
List<string> testLst = new List<string> { "LM.CHARLET", "L.MOURLIN", "Y.LEFEUVRE", "S.MIRO" }; var comparer = StringComparer.Create(CultureInfo.CurrentCulture, CompareOptions.IgnoreSymbols); List<string> orderedLst = testLst.OrderBy(p => p, comparer).ToList();
内容的提问来源于stack exchange,提问作者bod
相关产品推荐
相关产品推荐

