我们的应用程序有一个 CustomerNumber 领域。我们有数百个不同的人使用该系统(每个人都有自己的登录和它们自己的名单 CustomerNumbers)。个人用户可能有最多100 000名客户。许多低于100个。

有些人只是把实际数字,为他们的客户数领域,而其他人使用的混合物的东西。该系统允许20个字,这可以A-Z,0-9或一个破折号,并将这些在VARCHAR2(20).什么小写是由大写字之前被存储。

现在,让我们说,我们有一个简单的报告,其中列出了所有客户为一个特定用户,并按客户号码。例如

SELECT CustomerNumber,CustomerName
FROM Customer
WHERE User = ?
ORDER BY CustomerNumber;

这是一个天真的解决方案,为人们,永远只能使用的数字不希望看到一个普通的字母排序(其中"10"之前的"9").

我不希望询问用户的任何不必要的问题有关他们的数据。

我使用Oracle,但我认为这会很有趣,看到一些解决方案的其他数据库。请包括其数据库的应答工作。

你怎么认为最好的方式来实现这个是什么?

有帮助吗?

解决方案

在Oracle10g:

SELECT  cust_name
FROM    t_customer c 
ORDER BY
    REGEXP_REPLACE(cust_name, '[0-9]', ''), TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+'))

这将通过的第一次发生的数量,而不是关于它的位置,i。e:

  1. customer1 < customer2 < customer10
    • cust1omer ? customer1
    • cust8omer1 ? cust8omer2

, ,其中一个 ? 意味着为是不确定的。

这足够为大多数情况下。

要力量顺序排序上的情况 2, 你可以添加一个 REGEXP_INSTR(cust_name, '[0-9]', n)ORDER BY 列表 n 次,迫使顺序在第一次出现 n第(2nd, 3rd 等等)。 集团的数字。

要力量顺序排序上的情况 3, 你可以添加一个 TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+', n))ORDER BY 列表 n 次,迫使以的 n-th.集团的数字。

在实践中,查询我写的是足够的。

你可以创建一个功能的基于指数在这些表达方式,但你会需要力量,它暗示,一个通过 SORT ORDER BY 将进行无论如何,作为 CBO 不相信函数-基础的索引的,足以允许 ORDER BY 在他们身上。

其他提示

可能最好的方法是预先计算一个单独的列,并使用该订购,并使用客户编号进行显示。这可能会涉及填充0任何内部整数为固定长度。

另一种可能是做你的排序上返回的结果选后。

杰夫阿特伍德已经组建了一个博客张贴有关如何有人计算对人友好的排序顺序。

您可以具有数值列[CustomerNumberInt]为仅用于当为CustomerNumber是纯数字(NULL否则[1]),然后

ORDER BY CustomerNumberInt, CustomerNumber

[1]根据您的SQL版本ORDER BY,你可能需要将其默认为零点如何处理空值(或无穷大!)

我有一个类似的可怕状况和已经开发出一种合适的可怕函数来处理它(SQLServer的)

在我的情况我有“单位”(这是对学生工作跟踪系统,所以单位在这方面表示,他们正在做一个疗程)的表。单位有一个代码,其中大部分是纯粹的数字,但由于种种原因,被做了varchar,而他们决定由最多5个字符的前缀部分。因此,他们希望53123237356正常排序,但也T53,T123,T237,T356

UnitCode是nvarchar的(30)

这里的函数体:

declare @sortkey nvarchar(30)

select @sortkey = 
    case
        when @unitcode like '[^0-9][0-9]%' then left(@unitcode,1) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-1)
        when @unitcode like '[^0-9][^0-9][0-9]%' then left(@unitcode,2) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-2)
        when @unitcode like '[^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,3) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-3)
        when @unitcode like '[^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,4) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-4)
        when @unitcode like '[^0-9][^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,5) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-5)
        when @unitcode like '%[^0-9]%' then @unitcode
        else left('000000000000000000000000000000',30-len(@unitcode)) + @unitcode
    end 

return @sortkey

我想拍摄自己的脸书面之后,但它的作品,似乎不是在运行时杀死服务器。

我在SQL SERVER和工作极大使用这样的:在此解决方案是垫在前面一个字符的数字值,使得所有都是相同的字符串长度的

下面是使用该方法的示例:

select MyCol
from MyTable
order by 
    case IsNumeric(MyCol) 
        when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol
        else MyCol
    end

在100应该与该列的实际长度来代替。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top