【问题标题】:Version number sorting in Sql ServerSql Server 中的版本号排序
【发布时间】:2011-12-13 19:57:07
【问题描述】:

我有一个存储版本的表

Declare @tblVersion table(VersionNumber varchar(100))
 Insert into @tblVersion Values('1.3.1')
 Insert into @tblVersion Values('1.3.2.5')
 Insert into @tblVersion Values('1.4.1.7.12')
 Insert into @tblVersion Values('1.4.11.14.7')
 Insert into @tblVersion Values('1.4.3.109.1')
 Insert into @tblVersion Values('1.4.8.66')

 Select * From @tblVersion

VersionNumber
1.3.1
1.3.2.5
1.4.1.7.12
1.4.11.14.7
1.4.3.109.1
1.4.8.66

我的要求是我需要对它们进行排序,以便输出是

VersionNumber
1.3.1
1.3.2.5
1.4.1.7.12
1.4.3.109.1
1.4.8.66
1.4.11.14.7

但是如果做一个简单的命令,它就不能按预期工作

Select VersionNumber
 From @tblVersion
 Order By VersionNumber

VersionNumber
1.3.1
1.3.2.5
1.4.1.7.12
1.4.11.14.7
1.4.3.109.1
1.4.8.66

需要帮助

【问题讨论】:

  • 这是一般“不在列中存储分隔值”问题的特例

标签: sql sql-server tsql


【解决方案1】:

如果您使用的是 SQL Server 2008 或更高版本,则可以利用 hierarchyID 数据类型:

select * from @tblVersion
order by CAST('/'+REPLACE(VersionNumber,'.','/')+'/' as hierarchyID)

【讨论】:

  • 我刚刚意识到:您不需要将. 替换为/ORDER BY CAST('/'+VersionNumber+'/' as hierarchyID) 也可以。
【解决方案2】:

这通常称为自然排序,在 SQL Server 中没有简单的方法来做到这一点。通常需要将数据分成字段或字段的固定长度段。它可以按所需的顺序在那些字段上进行排序。

VersionNumber VersionSort
1.3.1         0001.0003.0001
1.3.2.5       0001.0003.0002.0005
1.4.1.7.12    0001.0004.0001.0007.0012
1.4.11.14.7   0001.0004.0011.0014.0007
1.4.3.109.1   0001.0004.0003.0109.0001
1.4.8.66      0001.0004.0008.0066

【讨论】:

    【解决方案3】:

    如果您使用的是 SQL Server 2005 或更高版本,并且版本号中可能的字段数是固定的,您可以尝试以下方法:

    SELECT t.*
    FROM @tblVersion t
      CROSS APPLY (SELECT v = NULLIF(CHARINDEX('.', '.' + t.VersionNumber,        1), 0)) v1
      CROSS APPLY (SELECT v = NULLIF(CHARINDEX('.', '.' + t.VersionNumber, v1.v + 1), 0)) v2
      CROSS APPLY (SELECT v = NULLIF(CHARINDEX('.', '.' + t.VersionNumber, v2.v + 1), 0)) v3
      CROSS APPLY (SELECT v = NULLIF(CHARINDEX('.', '.' + t.VersionNumber, v3.v + 1), 0)) v4
      CROSS APPLY (SELECT v = NULLIF(CHARINDEX('.', '.' + t.VersionNumber, v4.v + 1), 0)) v5
    ORDER BY
      CAST(SUBSTRING(t.VersionNumber, v1.v, v2.v - v1.v - 1) AS int),
      CAST(SUBSTRING(t.VersionNumber, v2.v, v3.v - v2.v - 1) AS int),
      CAST(SUBSTRING(t.VersionNumber, v3.v, v4.v - v3.v - 1) AS int),
      CAST(SUBSTRING(t.VersionNumber, v4.v, v5.v - v4.v - 1) AS int),
      CAST(SUBSTRING(t.VersionNumber, v5.v, 999) AS int)
    

    将版本号的所有字段一一提取并转换为整数,然后用于排序。 (基本上,@Brian 的想法,事实证明。)

    【讨论】:

      【解决方案4】:

      大脑解决方案的实现

      Declare @tblVersion table(VersionNumber varchar(100)) 
       Insert into @tblVersion Values('1.3.1') 
       Insert into @tblVersion Values('1.3.2.5') 
       Insert into @tblVersion Values('1.4.1.7.12') 
       Insert into @tblVersion Values('1.4.11.14.7') 
       Insert into @tblVersion Values('1.4.3.109.1') 
       Insert into @tblVersion Values('1.4.8.66') 
      
       --Select * From @tblVersion 
      
       ;With CTE AS
       (
          Select 
              Rn = Row_Number() Over(Order By (Select 1))
              ,VersionNumber
          From @tblVersion
      )
      ,CTESplit AS
      (
          SELECT 
                  F1.Rn,
                  F1.VersionNumber,
                  VersionSort = 
                                  Case 
                                          When Len(O.VersionSort) = 1 Then '000' + O.VersionSort
                                          When Len(O.VersionSort) = 2 Then '00' + O.VersionSort
                                          When Len(O.VersionSort) = 3 Then '0' + O.VersionSort
                                          When Len(O.VersionSort) = 4 Then O.VersionSort
                                  End
      
          FROM
          (
              SELECT *,
              cast('<X>'+replace(F.VersionNumber,'.','</X><X>')+'</X>' as XML) as xmlfilter from CTE F
          )F1
       CROSS APPLY
       ( 
          SELECT fdata.D.value('.','varchar(50)') as VersionSort  
          FROM f1.xmlfilter.nodes('X') as fdata(D)) O
       )
       ,CTE3 As(
      Select 
              --Rn 
              --,
              VersionNumber
              ,SortableVersion = 
                                  Stuff(
                                          (Select '.' + Cast(VersionSort As Varchar(100))
                                   From CTESplit c2
                                   Where c2.Rn = c1.Rn
                                   For Xml Path('')),1,1,'')
      From CTESplit c1
      Group By c1.Rn,c1.VersionNumber
      )
      Select VersionNumber
      From CTE3
      Order By SortableVersion
      

      【讨论】:

        【解决方案5】:

        我看不到使用标准排序等的解决方案,但我认为您需要在每个符号之前添加“0”符号的 UDF,例如

        001.003.001
        001.003.002.005
        001.004.001.007.012
        001.004.011.014.007
        001.004.003.109.001
        001.004.008.066
        

        然后按这些更改的值排序

        【讨论】:

          【解决方案6】:

          SELECT 查询是按字母顺序排列的,而不是按数字排列的。如果没有存储过程将前导零添加到版本号的单独组件中以使它们的长度相同,则无法(AFAIK)在 SQL 中执行此操作。

          【讨论】:

            【解决方案7】:

            检查这些对你有帮助

            Select * From @tblVersion order by replace(VersionNumber,'.','')

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-11-22
              • 1970-01-01
              • 2011-03-29
              • 1970-01-01
              • 1970-01-01
              • 2018-08-22
              • 2013-12-09
              • 1970-01-01
              相关资源
              最近更新 更多