【问题标题】:How Can I Sort A 'Version Number' Column Generically Using a SQL Server Query如何一般使用 SQL Server 查询对“版本号”列进行排序
【发布时间】:2011-03-29 08:10:45
【问题描述】:

我想知道我们当中的 SQL 天才是否可以帮我一把。

我在表 Versions 中有一个列 VersionNo,其中包含“版本号”值,例如

VersionNo
---------
1.2.3.1
1.10.3.1
1.4.7.2

等等

我希望对此进行排序,但不幸的是,当我执行标准 order by 时,它被视为字符串,因此排序结果为

VersionNo
---------
1.10.3.1
1.2.3.1
1.4.7.2

以下是我所追求的:

VersionNo
---------
1.2.3.1
1.4.7.2
1.10.3.1

所以,我需要做的是按相反的顺序对数字进行排序(例如,在 a.b.c.d 中,我需要按 d、c、b、a 排序以获得正确的排序)。

但我不知道如何以通用的方式实现这一目标。当然,我可以使用各种 sql 函数(例如 leftrightsubstringlencharindex)拆分字符串,但我不能保证总是有 4 个部分版本号。我可能有一个这样的列表:

VersionNo
---------
1.2.3.1
1.3
1.4.7.2
1.7.1
1.10.3.1
1.16.8.0.1

可以,有人有什么建议吗?非常感谢您的帮助。

【问题讨论】:

  • 在最后一种情况下,如果你没有 4 个要排序的东西,你希望它如何排序?
  • 看起来。那是我的问题,如果解决了就轻而易举了。

标签: sql sql-server sorting sql-server-2000


【解决方案1】:

另一种方法:

假设您只有 a,b,c,d,您也可以将数据分成列并按 a,b,c,d(all desc) 排序并获得前 1 行

如果您需要缩放到超过 d 来表示 e,f,g... 只需将 1,2,3,4 更改为 1,2,3,4,5,6,7 等等查询

查询: see demo

create table t (versionnumber varchar(255))
insert into t values
('1.0.0.505')
,('1.0.0.506')
,('1.0.0.507')
,('1.0.0.508')
,('1.0.0.509')
,('1.0.1.2')


; with cte as 
(
    select 
    column1=row_number() over (order by (select NULL)) ,
    column2=versionnumber
    from t
    )

select top 1
    CONCAT([1],'.',[2],'.',[3],'.',[4])
from 
(
    select 
        t.column1,
        split_values=SUBSTRING( t.column2, t1.N, ISNULL(NULLIF(CHARINDEX('.',t.column2,t1.N),0)-t1.N,8000)),
        r= row_number() over( partition by column1 order by t1.N) 
    from cte t 
        join
        (
            select 
                t.column2,
                1 as N 
            from cte t  
                UNION ALL
            select 
                t.column2,
                t1.N + 1 as N
            from cte t 
                join
                (
                 select 
                    top 8000
                        row_number() over(order by (select NULL)) as N 
                 from 
                    sys.objects s1 
                        cross join 
                   sys.objects s2 
                ) t1 
            on SUBSTRING(t.column2,t1.N,1) = '.'
         ) t1
          on t1.column2=t.column2
)a
pivot
( 
    max(split_values) for r in ([1],[2],[3],[4])
   )p
  order by [1] desc,[2] desc,[3] desc,[4] desc

【讨论】:

    【解决方案2】:

    如果您使用的是 SQL Server 2008

    select VersionNo from Versions order by cast('/' + replace(VersionNo , '.', '/') + '/' as hierarchyid);
    

    What is hierarchyid

    编辑:

    2000、2005、2008 年的解决方案:Solutions to T-SQL Sorting Challenge here

    The challenge

    【讨论】:

    • 会不会。但不幸的是,我坚持使用旧的 SQL 2000。
    • @James Wiseman:在链接中您应该找到适合您的解决方案。
    • @James - 不确定你最终使用的是什么。您也可以为此使用parsename,如此答案stackoverflow.com/questions/3057532/…
    • @Martin:我实际上使用过这个,但我也喜欢你的建议。谢谢。
    • 似乎不需要替换点。你可以使用这个:select * from Versions order by cast('/' + VersionNo + '/' as hierarchyid);
    【解决方案3】:

    依赖于 MySQL 的 SQL 引擎会是这样的:

    SELECT versionNo FROM Versions
    订购方式
    SUBSTRING_INDEX(versionNo, '.', 1) + 0,
    SUBSTRING_INDEX(SUBSTRING_INDEX(versionNo, '.', -3), '.', 1) + 0,
    SUBSTRING_INDEX(SUBSTRING_INDEX(versionNo, '.', -2), '.', 1) + 0,
    SUBSTRING_INDEX(versionNo, '.', -1) + 0;

    对于 MySQL 3.23.15 及以上版本

    SELECT versionNo FROM Versions ORDER BY INET_ATON(ip);

    【讨论】:

    • 它的 SQL Server 如标签所示,但已相应更新了我的问题。
    • 终于找到了一个可行的解决方案,谢谢!请注意,如果数字并非全部低于 256,INET_ATON 将无法正常工作。
    【解决方案4】:

    如果可以,请更改架构,使版本有 4 列而不是 1 列。然后排序很容易。

    【讨论】:

    • 哈哈,是的,我想到了,不幸的是,这不是一个选择。此外,长度可能是可变的,我不能保证最大列数为 4 或其他任何值。
    • 如果您使用的是 SQL Server 2005(可能是 2008,需要仔细检查)或更高版本,您可以编写一个 .NET CLR 方法来进行比较,或者更好的是,转换任意将版本号转换为规范的、可排序的格式(例如,将每个部分填充为 5 位数字);用你的数据库注册这个 CLR 方法,你可以像普通的 SQL 函数一样调用它。否则,您将无法在 SQL 中实现相同的功能,这可能对您的性能不利。
    • 是的,不幸的是,它是 VB6 和 SQL 2000 中的旧内部应用程序。
    猜你喜欢
    • 1970-01-01
    • 2011-05-18
    • 2020-02-27
    • 2013-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 2010-10-03
    相关资源
    最近更新 更多