2016-10-19 36 views
1

我有一个表格,其文件名和版本颠覆由.分隔的文件。订购版本号为

FNAME, VERSION 
A  0.0.10 
B  10.12.412 

-- For example 
create table file_versions as 
select chr(mod(level,13)+65) as fname 
    , decode(mod(level,99),0, '0', 
      mod(level,10)||'.'||mod(level,500)||'.'||mod(level,14) 
     ) 
     as version 
    from dual connect by level < 1001; 

我想用版本命令文件,但使用的版本为数字

select fname, version from file_versions 
order by fname, version 

FNAME, VERSION 
A  0.0.10 
A  0.0.6 
... 

我想不会去想颠覆级(可能有一个数(0)或更多(1.23.14123))。我应该如何按声明书写顺序?

我可以写类似:

select fname, version from file_versions 
order by fname 
     , to_number(substr(version, 1, instr(version, '.',1,1)-1)) 
     , to_number(substr(version, instr(version, '.',1,1)+1, instr(version, '.',1,2)-instr(version, '.',1,1)-1)) 
     , to_number(substr(version, instr(version, '.',1,2)+1)) 

但它不是那么好,如果一个数字被添加到版本字符串(例如0.0.0.123)将无法正常工作。有更好的解决方案吗?

回答

2

您可以使用两个正则表达式首先为增强你组5个零添加到任何组。另一个取每个组的最后5位数字。你可以得到恒定长度的行,并能够将它们分类为字符。

with s(txt) as (select '1' from dual 
      union all 
      select '1.12' from dual 
      union all 
      select '1.12.410' from dual 
      union all 
      select rpad('1.12.410',401,'.03') from dual 
      union all 
      select rpad('1.12.410',401,'.03')||'.01' from dual 
      union all 
      select rpad('1.12.410',401,'.03')||'.02' from dual    
) 
select txt,regexp_replace(regexp_replace(txt, '(\d+)','00000\1'),'\d+ (\d{5})','\1') from s 
order by regexp_replace(regexp_replace(txt, '(\d+)','00000\1'),'\d+(\d{5})','\1') 

它将工作到99999版本或颠覆。

+0

'\ d +(\ d {5})'中有奇怪的空格 –

3

您可以使用regexp_substr()

order by fname, 
     cast(regexp_substr(version, '[^.]+', 1, 1) as number), 
     cast(regexp_substr(version, '[^.]+', 1, 2) as number), 
     cast(regexp_substr(version, '[^.]+', 1, 3) as number) 
+0

谢谢。它可以在3个子级别上正常工作。但是更多的颠覆级别呢? –

+1

只需以相同的方式添加它们即可。除非你有超过1000个关卡(我怀疑它),它会起作用。 –

+0

@Michael Piankov:上面的排序顺序工作*高达* 3级。因此,添加行让它可以工作达到n级。 –

1

为了好玩而不是作为一个严肃的建议,下面是解析字符串的替代方法 - 将版本号视为inet地址。

,当你在你的版本三级棘手,但平凡的四个层次:你可以在三个层次的版本

select a.i::varchar 
from (select '192.168.100.128'::inet i union 
     select '22.168.100.128'::inet) a 
order by 1; 

     i   
-------------------- 
192.168.100.128/32 
22.168.100.128/32 
(2 rows) 

所以:

with 
    versions as (
    select '1.12.1' v union 
    select '1.3.100'), 
    inets as (
    select (v||'.0')::inet i 
    from versions) 
select substr(i::varchar,1,length(i::varchar)-5) 
from inets 
order by i; 

substr 
--------- 
1.3.100 
1.12.1 
(2 rows) 

与理念出发

也许每个人都应该有四个级别的版本...