我有一个名为MR的列,它是一个varchar。当我使用ORDER BY运行查询时,似乎没有正确排序。
select MR, LName, FName
from users
order by MR
结果:
MR | LNAME | FNAME
----------+-------+-------
1234-234 | HEN | LO
2343MA2 | SY | JACK
MR20001 | LINA | MARY
MR200011 | TEST | CASE
MR20002 | KO | MIKE
为什么MR200011会在MR20002之前显示? 任何想法家伙如何正确排序这个? MR的格式不固定。
答案 0 :(得分:1)
您按字符串排序,而不是按数字值排序。位置7中的角色是被比较的差异:
MR200011
MR20002
^
因为'2'> '1',这是你最终的订单。永远不会比较第8个字符,因为基于字符的排序顺序不依赖于它。
要“修复”此问题,请创建一个存储函数,该函数获取varchar值,并返回一个新的“排序字符串”,将数字组件填充到固定长度。
e.g。
MR20002 -> MR0020002
MR200011 -> MR0200011
但更重要的是,如果你有两个数字块,它们不会被破坏:
A1234-234 -> A000000001234-000000000234
A1234-5123 -> A000000001234-000000005123
以下函数在sql-server上执行此转换 - 您必须为mysql调整此函数:
create function dbo.get_numeric_sort_key(@value varchar(100))
returns varchar(200)
as
begin
declare @pad_characters varchar(12)
declare @numeric_block varchar(12)
declare @output varchar(200)
set @pad_characters = '000000000000'
set @output = ''
set @numeric_block = ''
declare @idx int
declare @len int
declare @char char(1)
set @idx = 1
set @len = len(@value)
while @idx <= @len
begin
set @char = SUBSTRING(@value, @idx, 1)
if @char in ('0','1','2','3','4','5','6','7','8','9')
begin
set @numeric_block = @numeric_block + @char
end
else
begin
if (@numeric_block <> '')
begin
set @output = @output + right(@pad_characters + @numeric_block, 12)
set @numeric_block = ''
end
set @output = @output + @char
end
set @idx = @idx + 1
end
if (@numeric_block <> '')
set @output = @output + right(@pad_characters + @numeric_block, 12)
return @output
end
然后更改您的order by
子句以使用新功能:
select MR, LName, FName
from users
order by dbo.get_numeric_sort_key(MR)
如果您有大量数据,则值得在表定义的末尾添加计算字段(由此函数填充),这样您每次运行此查询时都不必进行扫描
答案 1 :(得分:0)
只有当所有条目的长度都固定时,数字和字母的组合才能正确排序。在您的情况下,MR200011和MR20002的长度不相等,并且基于完成排序 MR200011 MR20002? 缺少第8个角色
答案 2 :(得分:0)
也许这个查询看起来不太好,但它会按照你想要的顺序对行进行排序:
select
MR,
LName,
FName
from (
select
MR,
LName,
FName,
least(
case when locate('0', MR)>0 then locate('0', MR) else length(MR)+1 end,
case when locate('1', MR)>0 then locate('1', MR) else length(MR)+1 end,
case when locate('2', MR)>0 then locate('2', MR) else length(MR)+1 end,
case when locate('3', MR)>0 then locate('3', MR) else length(MR)+1 end,
case when locate('4', MR)>0 then locate('4', MR) else length(MR)+1 end,
case when locate('5', MR)>0 then locate('5', MR) else length(MR)+1 end,
case when locate('6', MR)>0 then locate('6', MR) else length(MR)+1 end,
case when locate('7', MR)>0 then locate('7', MR) else length(MR)+1 end,
case when locate('8', MR)>0 then locate('8', MR) else length(MR)+1 end,
case when locate('9', MR)>0 then locate('9', MR) else length(MR)+1 end) pos
from users
) users_pos
order by
left(MR, pos-1),
mid(MR, pos, length(MR)-pos+1)+0
在子查询users_pos中的我正在计算一个数字的第一个位置,然后按left(MR, pos-1)
排序,这是字符串的非数字开头,而mid(MR, pos, length(MR)-pos+1)+0
是{{1}}字符串的数字部分,添加0将转换为数字并按数字排序(因此20002在200011之前出现)。
看到它正常工作here。