Sql 如何按照用户的期望对字母和数字的混合列表进行排序和显示?
我们的应用程序有一个Sql 如何按照用户的期望对字母和数字的混合列表进行排序和显示?,sql,database,alphanumeric,natural-sort,Sql,Database,Alphanumeric,Natural Sort,我们的应用程序有一个CustomerNumber字段。我们有数百名不同的用户使用该系统(每个人都有自己的登录名和自己的CustomerNumbers列表)。单个用户最多可能有100000个客户。许多人的收入不到100英镑 有些人只在他们的客户编号字段中输入实际数字,而其他人则混合使用。系统允许20个字符,可以是A-Z、0-9或破折号,并将这些字符存储在VARCHAR2(20)中。任何小写字母在存储之前都会变成大写 现在,假设我们有一个简单的报告,其中列出了特定用户的所有客户,并按客户编号排序。e
CustomerNumber
字段。我们有数百名不同的用户使用该系统(每个人都有自己的登录名和自己的CustomerNumber
s列表)。单个用户最多可能有100000个客户。许多人的收入不到100英镑
有些人只在他们的客户编号字段中输入实际数字,而其他人则混合使用。系统允许20个字符,可以是A-Z、0-9或破折号,并将这些字符存储在VARCHAR2(20)中。任何小写字母在存储之前都会变成大写
现在,假设我们有一个简单的报告,其中列出了特定用户的所有客户,并按客户编号排序。e、 g
SELECT CustomerNumber,CustomerName
FROM Customer
WHERE User = ?
ORDER BY CustomerNumber;
这是一个天真的解决方案,因为那些只使用数字的人不希望看到简单的字母排序(其中“10”在“9”之前)
我不希望向用户询问有关其数据的任何不必要的问题
我正在使用Oracle,但我认为看到其他数据库的一些解决方案会很有趣。请包括您的答案使用的数据库
您认为实现这一点的最佳方法是什么?您最好的选择可能是预先计算一个单独的列,并使用该列进行订购,并使用客户编号进行显示。这可能涉及将任何内部整数填充到固定长度 另一种可能是对返回的结果进行排序后选择 关于一些人如何计算人性化排序顺序的帖子。在Oracle 10g中:
SELECT cust_name
FROM t_customer c
ORDER BY
REGEXP_REPLACE(cust_name, '[0-9]', ''), TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+'))
这将按照数字的第一次出现进行排序,而不考虑其位置,即。e、 :
customer1
cust1omer?客户1
customer1?客户2
?
表示订单未定义
这在大多数情况下就足够了
要强制对案例2
进行排序,您可以将REGEXP_INSTR(客户名称,[0-9]',n)
添加到按列表n
次排序,强制在n
-th(2nd
,3rd
等)数字组第一次出现时进行排序
要强制对案例3
排序,您可以将添加到\u编号(REGEXP\u SUBSTR(客户名称,[0-9]+',n))
到按次排序,强制顺序为n
-th。一组数字
实际上,我写的查询已经足够了
您可以根据这些表达式创建基于函数的索引,但需要使用提示强制执行,并且会执行一次通过的排序方式,因为CBO
对函数基索引的信任程度不足以允许对它们执行排序方式。您可以有一个数字列[CustomerNumber]仅当CustomerNumber为纯数字(否则为空[1])时才使用,然后
[1] 根据您的SQL版本按顺序处理空值的方式,您可能希望将其默认为零(或无限!)我遇到了类似的可怕情况,并开发了一个适当的可怕函数来处理它(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应该替换为该列的实际长度。另请参见,以及其他标记为“自然排序”的内容,以便讨论和实现。。。
select MyCol
from MyTable
order by
case IsNumeric(MyCol)
when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol
else MyCol
end