SQL:查找句点分隔版本的最大值

时间:2015-02-24 15:38:57

标签: sql-server

我在SQL Server 2008中有一个表,其中包含资源ID和某个文件的相应版本:

ResourceID    FileVersion
1             8.00.7601.17514 (win7sp1_rtm.101119-1850)
1             11.00.9600.16428 (winblue_gdr.131013-1700)
1             11.00.9600.17041 (winblue_gdr.140305-1710)
1             11.00.9600.17126 (winblue_gdr_escrow.140529-2055)
2             8.00.7601.18472 (win7SP1_GDR_escrow.140527-0630)
2             8.00.7601.22686 (win7SP1_LDR_escrow.140527-0630)
2             11.00.9600.17239 (winblue_gdr.140724-2228)
2             11.00.9600.17420 (winblue_r4.141105-1535)
2             11.00.9600.17496 (winblue_r5.141121-1500)

我想找到每个资源ID的最大版本。在这种情况下,所需的输出是

ResourceID    FileVersion
1             11.00.9600.17126 (winblue_gdr_escrow.140529-2055)
2             11.00.9600.17496 (winblue_r5.141121-1500)

我尝试过以下代码:

Select ResourceID, MAX(SUBSTRING(FileVersion,1,CHARINDEX(' ',FileVersion + ' ')-1))
From VersionTable
Group By ResourceID

但是得到以下输出:

ResourceID    FileVersion
1             8.00.7601.17514 (win7sp1_rtm.101119-1850)
2             8.00.7601.22686 (win7SP1_LDR_escrow.140527-0630)

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:1)

要使排序正常工作,您基本上没有多少选择:

1)向表中添加一个或多个计算列,可能每个数组或一个bigint一个。有4个单独的列可能是更安全的选择。

2)将4部分字符串拆分为select,将每个由句点分隔的部分转换为数字,并将数据排序为整数。如果你在几个地方有类似的逻辑,那么你最终会在整个地方复制粘贴相同的代码。

3)创建一个用户定义的函数,从版本字符串返回4个数字。易于在多个地方使用,但可能会导致性能开销。

4)在表的顶部创建一个创建版本整数的视图。基本上和功能一样,如果有很多行(或经常被称为),那就不是最好的了。

编辑:为视图添加了想法。

编辑2:添加了选择的示例:

select
  ResourceID,
  ver
from (
  select
    ResourceID,
    v.ver,
    row_number() over (partition by ResourceID 
        order by n.v1 desc, n.v2 desc, n.v3 desc, n.v4 desc) as rn
  from VersionTable
  cross apply (
    select left(FileVersion, charindex(' ', FileVersion)-1) as ver
  ) as v
  cross apply (
    select charindex('.', v.ver) as p
  ) as p1
  cross apply (
     select charindex('.', v.ver, p1.p+1) as p
  ) as p2
  cross apply (
     select charindex('.', v.ver, p2.p+1) as p
  ) as p3
  cross apply (
    select 
      convert(int, left(v.ver, p1.p - 1)) as v1,
      convert(int, substring(v.ver, p1.p+1, p2.p-p1.p-1)) as v2,
      convert(int, substring(v.ver, p2.p+1, p3.p-p2.p-1)) as v3,
      convert(int, substring(v.ver, p3.p+1, 999)) as v4
  ) as n
) tmp
where rn = 1

答案 1 :(得分:1)

这是一个黑客,可能不会一直有效,但它确实对您的示例数据有所帮助,应该让您知道您可以做什么:

Select 
    ResourceID, 
    max(
       case 
          when charindex('.', fileversion, 0) = 2 
          then STUFF(LEFT(FileVersion, CHARINDEX(' ', FileVersion,0)-1), 1, 1, '0'+left(fileversion, 1))
       else LEFT(FileVersion, CHARINDEX(' ', FileVersion,0)-1) 
       end
       )
From VersionTable
group by ResourceID

如果第一个数字为0-9,则输入0,使其变为00-09,从而改变词汇顺序。

答案 2 :(得分:0)

如果你知道你将永远拥有像number.number.number.number

这样的FileVersion表

此代码可以使用。基本上它为版本的每个部分创建4个整数,并从左侧开始按顺序排序(重要性更高的数字)

SELECT * FROM VersionTable
    ORDER BY substring([FileVersion],0,charindex('.',[FileVersion])) DESC,
    substring(substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion])),0,charindex('.',substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion])))) DESC,
    substring(substring(substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion])),charindex('.',substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion])))+1,LEN(substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion]))))
    ,0,charindex('.',substring(substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion])),charindex('.',substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion])))+1,LEN(substring([FileVersion],charindex('.',[FileVersion])+1,LEN([FileVersion])))))),

    reverse(substring(reverse([FileVersion]), 0 , charindex('.',reverse([FileVersion])))) DESC

这将为您的表值排序,而不是为每个资源选择一个。