2016-10-19 40 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) 

與理念出發

也許每個人都應該有四個級別的版本...