拆分一个字符串并在mssql中返回最大值

时间:2011-07-28 07:44:52

标签: sql sql-server string-comparison

我需要找到一种方法来获取具有最高版本号的数据。

这是我的数据库设计:

VERSIONNUMBER - varchar(15)
DOWNLOADPATH - varchar(100)

假设我有以下记录:

VERSIONNUMBER -------- DOWNLOADPATH
1.1.2                  a.com
1.1.3                  b.com
2.1.4                  c.com
2.1.5                  d.com
2.2.1                  e.com

我需要使用版本号2.2.1获取记录。需要一些sql的帮助,但是:)

感谢您的帮助

7 个答案:

答案 0 :(得分:4)

试试这个:

with a as
(
    select * from (values
    ('1.1.2'),('1.1.3'),('2.1.4 '), ('2.1.5'), ('2.2.1') ) as b(c)
)
select c, PARSENAME(c,1),PARSENAME(c,2), PARSENAME(c,3)
from a
order by 
convert(int,PARSENAME(c,3)),
convert(int,PARSENAME(c,2)),
convert(int,PARSENAME(c,1))

灵感来自:http://www.sql-server-helper.com/tips/sort-ip-address.aspx

with a as
(
    select * from (values
    ('1.1.2'),('1.1.3'),('2.1.4 '), ('2.1.5'), ('2.2.1') ) as b(c)
),
x as 
(
    select c, 
       convert(int,PARSENAME(c,3)) * 100 
       + convert(int,PARSENAME(c,2)) * 10 
       + convert(int,PARSENAME(c,1)) * 1 as the_value
    from a
)
select c from x where the_value = (select MAX(the_value) from x)

在软件开发中,通常会找到一个包含两位数的次要版本号,版本号与数字值没有任何关系,因此版本1.12大于1.5;为了弥补这一点,你必须填充数字:

    -- Use this, the query above is not future-proof :-)
with a as
(
    select * from (values
    ('2.1.4 '), ('2.1.12'), ('2.1.5'), ('2.2.1') ) as b(c)
),
x as 
(
    select c, 
       convert(int,PARSENAME(c,3)) * 100*100*100 
       + convert(int,PARSENAME(c,2)) * 100*100 
       + convert(int,PARSENAME(c,1)) * 100 as the_value
    from a
)
select c, the_value from x   
order by the_value

输出:

2.1.4   2010400
2.1.5   2010500
2.1.12  2011200
2.2.1   2020100

如果您不考虑这一点(如以下查询):

with a as
(
    select * from (values
    ('2.1.4 '), ('2.1.12'), ('2.1.5'), ('2.2.1') ) as b(c)
),
x as 
(
    select c, 
       convert(int,PARSENAME(c,3)) * 100
       + convert(int,PARSENAME(c,2)) * 10
       + convert(int,PARSENAME(c,1)) * 1 as the_value
    from a
)
select c, the_value from x   
order by the_value;


    -- KorsG's answer has a bug too
with a as
(
    select * from (values
    ('2.1.4 '), ('2.1.12'), ('2.1.5'), ('2.2.1') ) as b(c)
),
x as 
(
    select c, 
       CAST(REPLACE(c, '.', '') AS int) as the_value
    from a
)
select c, the_value from x   
order by the_value      

这两个查询将产生相同(不正确)的输出:

c           the_value
2.1.4   214
2.1.5   215
2.2.1   221
2.1.12  222

2.2.1和2.1.12的值重叠。当您仅删除点并将结果字符串直接转换为int时,也会发生这种情况。 2.1.12成为二千一百二十二,2.2.1成为二百二十二。 2.2.1大于2.1.12,不小于

答案 1 :(得分:2)

select top 1 DOWNLOADPATH
from YourTable
order by cast(parsename(VERSIONNUMBER, 3) as int) desc,
         cast(parsename(VERSIONNUMBER, 2) as int) desc,
         cast(parsename(VERSIONNUMBER, 1) as int) desc

答案 2 :(得分:1)

或者,您可以使用排名:

,而不是将每个数字组相乘
with a as
(
    select * from (values
        ('2.1.4 '), ('2.1.12'), ('2.1.5'), ('2.2.1') 
    ) as b(c)     
),
x as
(
select c, 
    Ranking = RANK() over(order by convert(int,PARSENAME(c,3)), convert(int,PARSENAME(c,2)), convert(int,PARSENAME(c,1))) 
from a
)
select * from x 
    order by ranking

收率:

c   Ranking
2.1.4   1
2.1.5   2
2.1.12  3
2.2.1   4

最终查询:

with a as
(
    select * from (values
        ('2.1.4 '), ('2.1.12'), ('2.1.5'), ('2.2.1') 
    ) as b(c)     
),
x as
(
select c, 
    Ranking = RANK() over(order by convert(int,PARSENAME(c,3)), convert(int,PARSENAME(c,2)), convert(int,PARSENAME(c,1))) 
from a
)
select * 
from x  
where Ranking = (select MAX(ranking) from x)

输出:

c   Ranking
2.2.1   4

另一个简单的方法,排序降序然后得到第一行:

with a as
(
    select * from (values
        ('2.1.4 '), ('2.1.12'), ('2.1.5'), ('2.2.1') ) as b(c)     
),
x as
(
select c, 
    Ranking = RANK() 
        over(order by 
            convert(int,PARSENAME(c,3)) desc, 
            convert(int,PARSENAME(c,2)) desc, 
            convert(int,PARSENAME(c,1)) desc) 
from a
)
select * 
from x  
where Ranking = 1

答案 3 :(得分:1)

如果您使用的是SQL Server 2008,则可以使用HIERARCHYID数据类型。

SELECT VersionNumber, DownloadPath
FROM (VALUES
    ('1.1.2','a.com'),
    ('1.1.3','b.com'),
    ('2.1.4','c.com'),
    ('2.1.5','d.com'),
    ('2.2.1','e.com')        
     ) AS T(VersionNumber, DownloadPath)
ORDER  BY CAST('/' + VersionNumber + '/' AS HIERARCHYID) DESC

答案 4 :(得分:0)

这样可行,但它并不漂亮 - 我肯定会考虑更改存储版本号的方式。

concat( 
right(concat(repeat("0",5), substring_index(VERSIONNUMBER,".",1)),5),
right(concat(repeat("0",5), substring_index(substring_index(VERSIONNUMBER,".",2),".",-1)),5),
right(concat(repeat("0",5), substring_index(VERSIONNUMBER,".",-1)),5))

基本上它会将"1.24.937"转换为"000010002400937",然后将其正确排序为字符串。

答案 5 :(得分:0)

就我个人而言,我喜欢@Mikael的版本,但显然这对其他RDBMS来说并不那么便携......

这个怎么样?快速和脏,适用于三个数字版本(如您的示例中所示。)

这里的hack是要意识到“2.59”,例如,是一个有效的数字,只是一个有效的整数,所以你只需要在一个地方拆分字符串 - 你想要主要的版本号,以及休息。这很可怕,但当它出现时,我想我会分享它,因为它至少是而且很可怕。

SELECT 
   TOP 1 downloadpath 
FROM 
   version_table 
ORDER BY 
   CAST(LEFT(VERSIONNUMBER, CHARINDEX( '.', VERSIONNUMBER) - 1) AS INTEGER) DESC,
   CAST(SUBSTRING(VERSIONNUMBER, CHARINDEX( '.', VERSIONNUMBER) + 1, 100) AS FLOAT) DESC

当然,真正的答案是将您的数据库设计更改为拆分版本号或包含内部版本号或类似内容......

答案 6 :(得分:-2)

SELECT downloadpath FROM TABLE
WHERE versionnumber = (SELECT MAX(VersionNumber) FROM TABLE)

也可能有一种更漂亮的方式。