SQL Server的自然排序

时间:2015-02-06 18:26:40

标签: c# sql-server sorting dataview natural-sort

类似问题

之前已经提出了类似的问题,但是数据总是具有特定的特性,这些特性允许更有针对性的分解,并且只是按照这一部分进行排序。方法,当你不知道列中的数据结构 - 甚至是列时,这种方法不起作用。换句话说,不是通用的,"自然"排序顺序 - 大致相当于SELECT * FROM [parts] ORDER BY [part_category] DESC, [part_number] NATURAL DESC

的顺序

我的情况

我在C#中有一个DataView,其Sort参数用于指定ADO将使用的ORDER BY,并且需要使用' natural&#39按列排序;排序算法。从理论上讲,我可以做任何事情,从创建不同的列到排序依据(基于列我希望自然排序')不在SQL中排序,而是对结果进行排序之后在代码中设置。我正在寻求灵活性,效率,准备工作和可维护性之间的最佳平衡。我可以通过在检索(在C#中)或完全在存储过程中对这些数据进行排序来获益。

在我看来,根据客户的声明,到目前为止,' Natural'排序顺序意味着同等地处理大写和小写字母,并考虑数字的幅度,而不是其数字的ASCII值(即x90 之前 em> x100)。杰夫阿特伍德有一个pretty decent discussion of this,但它并没有解决SQL排序问题。那就是说,这些是我的想法:

  • 结合大小意识,同时保留对ASCII字符字符进行排序的能力也可以派上用场
  • 非字母数字字符可能必须以ASCII-betically方式排序,无论
  • 小数点意识可能比它的价值更大,因为字母数字字段中的大部分时间段和逗号仅被视为标点符号/分隔符,并且仅表示当它们表示的小数部分时浮动字段

我的问题

为SQL实现自然排序算法的合理灵活,合理通用,合理有效的方法是什么?权衡利弊,哪种方法最好?还有其他选择吗?

  • 是否有ORDER BY [field] NATURAL DESC或其他东西的原生SQL方式?
  • PURE SQL函数用于创建等效的' - 可用于创建某种第二种,可能是索引的'排序值'列,或从存储过程调用,或在“排序”中指定。子句 - 但如何有效地写它? (循环?是否有基于集合的解决方案?)
  • CLR SQL函数 - 纯SQL函数的可用性好处,但是使用过程语言,比如C#(算法应该没问题,但是它可以比纯SQL排序[基于集合的]实现更快吗?)此外,如果效率足够,可以在C#中引用和使用。
  • 避免使用SQL Server - 因为在各种其他字符中解析任意数量的数字最适合循环或递归,而T-SQL不适合循环或递归(尽管技术支持,我只看到了“不要使用LOOPS !!!' CTE更糟糕!!!')
  • SQL中的某种比较器(??) - 似乎没有SQL适合这种排序,我也没有看到指定比较器使用的方法 - 所以我猜这个不会工作......

我的价值至少与以下不同:

100s455t
200s400
d399487
S0000005.2
d400400
d99222
cg9876
D550-9-1
CL2009-3-27
f2g099
f2g100
f2g1000
f2g999
cg 8837
99s1000f

这些应按如下方式排序:

99s1000f
100s455t
200s400
cg9876
cg 8837
CL2009-3-27
D550-9-1
d99222
d399487
d400400
f2g099
f2g100
f2g999
f2g1000
S0000005.2

3 个答案:

答案 0 :(得分:1)

创建排序列。这样你就可以保留你今天用来排序的所有常用机制。例如,您可以索引该列。

将字符串拆分为多个部分。您需要用零填充数字部分到最大可能的数字长度。

例如CL2009-3将成为CL|000002009|-|000000003

这样,通常不区分大小写的SQL Server排序规则排序行为将创建正确的顺序。

自然排序动态地阻止索引,要求整个数据集针对每个查询移动到应用程序中并且是资源密集型的。

相反,只需在更新基本列时更新排序列。

答案 1 :(得分:0)

行。这是几乎您正在寻找的东西。它唯一可以处理的是当有一些字符然后是空格然后是数字(cg 8837和cg9876)。如果将来您可以发布ddl和示例数据以便我们可以使用它,那就太好了。

with Something (SomeValue) as(
    select '100s455t' union all
    select '200s400' union all
    select 'd399487' union all
    select 'S0000005.2' union all
    select 'd400400' union all
    select 'd99222' union all
    select 'cg9876' union all
    select 'D550-9-1' union all
    select 'CL2009-3-27' union all
    select 'f2g099' union all
    select 'f2g100' union all
    select 'f2g1000' union all
    select 'f2g999' union all
    select 'cg 8837' union all
    select '99s1000f'
)

select * 
from Something
order by
    cast(
    case when patindex('%[A_Za-z]%', SomeValue) = 1 then '99999999999'
         when patindex('%[A_Za-z]%', SomeValue) = 0 then SomeValue
         else substring(SomeValue, 1, patindex('%[A_Za-z]%', SomeValue) - 1)
    end as bigint),
    SomeValue

答案 2 :(得分:-1)

我建议"远离SQL Server"。虽然从技术上讲,您可以使用t-sql或clr函数实现所有内容,但SQL Server仍然是基础结构的单个不可伸缩单元。使用其CPU资源进行繁重的计算通常会不可避免地影响系统的性能。最后,SQL服务器将使用几乎完全相同的算法执行排序,您将使用该算法对应用程序端的数组进行排序,即查看数组中的每个项目并将其与其他项目进行比较,直到找到合适的位置。

当然我假设,如果你尝试在SQL服务器端实现这种类型的排序,你将在执行排序之前将数据复制到临时表中,以避免数据锁等。