【问题标题】:SQL sort by version "number", a string of varying lengthSQL按版本“编号”排序,长度不等的字符串
【发布时间】:2009-02-09 16:24:25
【问题描述】:

我正在尝试创建一个 SQL 查询,它将按版本号(例如 1.1、4.5.10 等)对结果进行排序

这是我尝试过的:

SELECT * FROM Requirements 
    WHERE Requirements.Release NOT LIKE '%Obsolete%' 
    ORDER BY Requirements.ReqNum

现在,ReqNum 字段是一个字符串字段,不幸的是我无法将其更改为浮点数或类似的东西,因为我有像 162.1.11 这样的需求编号。

当我得到结果后,我会得到这样的订单:

1.1
1.10
1.11
1.3

如何编写一个按字典顺序排序的查询?

...或者,

如何正确排序数据?

感谢您提前输入!

【问题讨论】:

  • 版本号有最大级别数吗?
  • 我认为我见过的最高级别是四个级别(例如1.22.3.4)
  • 但是您当前的排序顺序应该已经按字典顺序排序了吗?你能举一个排序不正确的例子吗?
  • 如果在 SQL Server 2008+ 上HierarchyId can be used for this

标签: sql


【解决方案1】:

在 PostgreSQL 中你可以这样做:

SELECT * FROM Requirements
ORDER BY string_to_array(version, '.')::int[];

最后一个::int[] 使其将字符串值转换为整数,然后进行比较。

【讨论】:

  • 这肯定是这里所有答案中最简单和最有效的?
  • @donnek 同意。
  • 如果我删除 "::int[]" 会发生什么? ORDER BY string_to_array(version, '.')::int[];我有一些产品版本,例如:3.3.0-beta 这是一个有效的 SEMVER 版本。
  • 不幸的是,这在某些情况下效果不佳。例如,使用此公式,版本“2.4.0+9”排在“2.4.0+10”之前。那是假设您删除了“::int[]”,否则它将不起作用。
【解决方案2】:

为获得最佳结果,请重构版本号存储,以便每个部分都有自己的列:MajorVersion、MinorVersion、Revision、Build。然后排序问题突然变得微不足道。您还可以构建一个计算列,以便于检索完整的字符串。

【讨论】:

  • 这不是一个坏主意,而且绝对是我遇到的一个 - 问题是我必须手动为大约 600 列执行此操作。
  • 列?你是说桌子?您应该能够编写脚本。
  • 打败我。不,您不必手动操作。您可以使用 UPDATE 语句来填充它们。
  • 嗯,我有点喜欢 UPDATE 的想法 - 我会保持这个开放时间更长一点,看看是否有任何其他创造性的想法出现。谢谢各位!
  • 另外,如果需要时间来更改想要以旧方式插入字符串的现有代码,请考虑添加一个触发器来填充新字段,直到一切都同步。
【解决方案3】:
SELECT * FROM Requirements 
WHERE Requirements.Release NOT LIKE '%Obsolete%' 
ORDER BY cast('/' + replace(Requirements.ReqNum , '.', '/') + '/' as hierarchyid);

【讨论】:

  • 请解释一下你的代码,解释代码比发布代码更有效率。
  • 很好,但不需要替换 '.'到'/',只需删除replace(Requirements.ReqNum , '.', '/') 部分,这样就足够了:ORDER BY cast('/' + Requirements.ReqNum + '/' as HIERARCHYID)
【解决方案4】:

@vuttipong-l answer (T-SQL) 略有不同

SELECT VersionNumber
FROM (
SELECT '6.1.3' VersionNumber UNION
SELECT '6.11.3' UNION
SELECT '6.2.3' UNION
SELECT '6.1.12' 
) AS q
ORDER BY cast('/' + VersionNumber + '/' as hierarchyid)

从 2008 年开始在 SQL Server 中工作,点在 hierarchyid 列的字符串表示中是可以的,因此我们不需要用斜杠替换它们。 来自文档的引用:

比较是通过比较分开的整数序列来执行的 按字典顺序按点。

但有一个警告:版本段不得以零为前缀。

【讨论】:

  • 我以为这里的“V”可能意味着“视图”,但实际上它只是一个表示“版本”的单字符列名。
【解决方案5】:

如果您在 SQL Server 领域...

DECLARE @string varchar(40)
SET @string = '1.2.3.4'
SELECT PARSENAME(@string, 1), PARSENAME(@string, 2), PARSENAME(@string, 3), PARSENAME(@string, 4)

结果: 4、3、2、1

对于解析 IP 地址和其他带点的项目很有用,例如版本号。 (您也可以使用 REPLACE() 将项目转换为点符号...例如 1-2-3-4 -> 1.2.3.4)

【讨论】:

  • 我知道这已经有几年的历史了,但这是我本月遇到的最有用的 hack。谢谢!
  • PARSENAME 有一个限制,最多只能使用 4 个子部分。
  • SELECT PARSENAME('1.2.3', 1), PARSENAME('1.2.3.4', 1) == 3, 4 不适合我的需要。
【解决方案6】:

如果您不按照 Joel Coehoorn 明智的建议重新设计表格,那么您需要将版本号重新格式化为按您需要排序的字符串,例如

  • 1.1 -> 0001.0001.0000
  • 162.1.11 -> 0162.0001.0011

这可以通过函数来​​完成,或者如果您的 DBMS 有这些,则可以使用计算/虚拟列。然后您可以在 ORDER BY 子句中使用该函数或列。

【讨论】:

    【解决方案7】:

    以下函数将采用版本号并将每个级别格式化为 3 位:

    用法:

    select * from TableX order by dbo.fn_VersionPad(VersionCol1)
    

    功能:

    CREATE FUNCTION [dbo].[fn_VersionPad]
    (
        @version varchar(20)
    )
    RETURNS varchar(20)
    AS
    BEGIN
        /*
            Purpose:  Pads multi-level Version Number sections to 3 digits
            Example:  1.2.3.4
            Returns:  001.002.003.004
        */
    
        declare @verPad varchar(20)
        declare @i int
        declare @digits int
    
        set @verPad = ''
    
        set @i = len(@version)
        set @digits = 0
    
        while @i > 0
        begin
            if (substring(@version, @i, 1) = '.')
            begin
                while (@digits < 3)
                begin
                    -- Pad version level to 3 digits
                    set @verPad = '0' + @verPad
                    set @digits = @digits + 1
                end
    
                set @digits = -1
            end
    
            set @verPad = substring(@version, @i, 1) + @verPad
    
            set @i = @i - 1
            set @digits = @digits + 1
        end
    
        while (@digits < 3)
        begin
            -- Pad version level to 3 digits
            set @verPad = '0' + @verPad
            set @digits = @digits + 1
        end
    
        return @verPad
    END
    

    【讨论】:

    • 此解决方案帮助我将版本字符串格式化为可比较的字符串。扩展 VARCHAR(20) 以支持超过 4 个部分。
    【解决方案8】:

    您可以使用 CHARINDEX / SUBSTR 和 ORDER BY 来拆分字符串(您已经知道分隔符:“.”)的不同部分。在函数中执行或逐个执行。

    它不会很漂亮,也不会很快:所以如果您需要快速查询,请关注 Tony 或 Joel。

    【讨论】:

      【解决方案9】:

      不使用代码

      Insert into @table
      Select 'A1' union all
      Select 'A3' union all
      Select 'A5' union all
      Select 'A15' union all
      Select 'A11' union all
      Select 'A10' union all
      Select 'A2' union all
      Select 'B2' union all
      Select 'C2' union all
      Select 'C22' union all
      Select 'C221' union all
      Select 'A7' 
      
      Select cod from @table
      Order by LEN(cod),cod 
      

      结果:

      A1
      A2
      A3
      A5
      A7
      B2
      C2
      A10
      A11
      A15
      C22
      C221
      

      很简单:

      Declare @table table(id_ int identity(1,1), cod varchar(10))
      
      Insert into @table
      Select 'A1' union all
      Select 'A3' union all
      Select 'A5' union all
      Select 'A15' union all
      Select 'A11' union all
      Select 'A10' union all
      Select 'A2' union all
      Select 'A7' 
      
      Select cod from @table
      Order by LEN(cod),cod  
      

      【讨论】:

        【解决方案10】:

        在 PostgreSQL 上,再简单不过了:

        SELECT ver_no FROM version ORDER BY string_to_array(ver_no, '.', '')::int[]

        【讨论】:

          【解决方案11】:

          如果您使用的是 Microsoft SQL Server,这将起作用:

          create function fnGetVersion (@v AS varchar(50)) returns bigint as
          begin
          declare @n as bigint;
          declare @i as int;
          select @n = 0;
          select @i = charindex('.',@v);
          while(@i > 0)
          begin
              select @n = @n * 1000;
              select @n = @n + cast(substring(@v,1,@i-1) as bigint); 
              select @v = substring(@v,@i+1,len(@v)-@i);
              select @i = charindex('.',@v);
          end
          return @n * 1000 + cast(@v as bigint);
          end
          

          通过运行以下命令进行测试:

          select dbo.fnGetVersion('1.2.3.4')
          

          这将返回完全可排序的数字 1002003004。您是否需要 9.0.1 大于 2.1.2.3 那么您需要稍微更改逻辑。在我的示例中,9.0.1 将排在 2.1.2.3 之前。

          【讨论】:

            【解决方案12】:

            PostgreSQL 函数

            简单使用

            select *
              from sample_table
             order by _sort_version(column_version);
            
            
            
            
            CREATE FUNCTION _sort_version (
              p_version text
            )
            RETURNS text AS
            $body$
            declare 
              v_tab text[];
            begin
              v_tab := string_to_array(p_version, '.');  
            
              for i in 1 .. array_length(v_tab, 1) loop
                v_tab[i] := lpad(v_tab[i], 4, '0');
              end loop;
            
              return array_to_string(v_tab, '.');
            end;
            $body$
            LANGUAGE 'plpgsql'
            VOLATILE
            CALLED ON NULL INPUT
            SECURITY DEFINER
            COST 1;
            

            【讨论】:

              【解决方案13】:

              我也遇到过同样的问题,虽然我的公寓号码是 A1、A2、A3、A10、A11 等,但他们想“正确”排序。如果将版本号拆分为单独的列不起作用,请尝试此 PL/SQL。它接受一个像 A1 或 A10 这样的字符串并将其扩展为 A0000001、A0000010 等,所以它的排序很好。只需在 ORDER BY 子句中调用它,就像

              选择 apt_num 从公寓 按 PAD(apt_num) 排序

              function pad(inString IN VARCHAR2)
                 return VARCHAR2
              
              --This function pads the numbers in a alphanumeric string.
              --It is particularly useful in sorting, things like "A1, A2, A10"
              --which would sort like "A1, A10, A2" in a standard "ORDER BY name" clause
              --but by calling "ORDER BY pkg_sort.pad(name)" it will sort as "A1, A2, A10" because this
              --function will convert it to "A00000000000000000001, A00000000000000000002, A00000000000000000010" 
              --(but since this is in the order by clause, it will
              --not be displayed.
              
              --currently, the charTemplate variable pads the number to 20 digits, so anything up to 99999999999999999999 
              --will work correctly.
              --to increase the size, just change the charTemplate variable.  If the number is larger than 20 digits, it will just
              --appear without padding.
              
              
                 is
                    outString VARCHAR2(255);
                    numBeginIndex NUMBER;
                    numLength NUMBER;
                    stringLength NUMBER;
                    i NUMBER;
                    thisChar VARCHAR2(6);
                    charTemplate VARCHAR2(20) := '00000000000000000000';
                    charTemplateLength NUMBER := 20;
              
              
                 BEGIN
                    outString := null;
                    numBeginIndex := -1;
                    numLength := 0;
                    stringLength := length(inString);
              
                    --loop through each character, get that character
                    FOR i IN 1..(stringLength) LOOP
                       thisChar := substr(inString, i, 1);
              
                       --if this character is a number
                       IF (FcnIsNumber(thisChar)) THEN
              
                          --if we haven't started a number yet
                          IF (numBeginIndex = -1) THEN
                             numBeginIndex := i;
                             numLength := 1;
              
                          --else if we're in a number, increase the length
                          ELSE 
                             numLength := numLength + 1;
                          END IF;
              
                          --if this is the last character, we have to append the number
                          IF (i = stringLength) THEN
                             outString:= FcnConcatNumber(inString, outString, numBeginIndex, numLength, charTemplate, charTemplateLength);
                          END IF;
              
                       --else this is a character
                       ELSE
              
                          --if we were previously in a number, concat that and reset the numBeginIndex
                          IF (numBeginIndex != -1) THEN
                             outString:= FcnConcatNumber(inString, outString, numBeginIndex, numLength, charTemplate, charTemplateLength);
                             numBeginIndex := -1;
                             numLength := 0;
                          END IF;
              
                          --concat the character
                          outString := outString || thisChar;
                       END IF;
                    END LOOP;
              
                    RETURN outString;
              
                 --any exception, just return the original string
                 EXCEPTION WHEN OTHERS THEN
                    RETURN inString;
              
                 END;     
              

              【讨论】:

                【解决方案14】:

                这是一个提取字符串的示例查询。您应该能够在数据库的 UPDATE 重构中使用它,或者简单地在查询中使用它。但是,我不确定它是如何准时的。只是需要注意和测试的东西。

                SELECT SUBSTRING_INDEX("1.5.32",'.',1) AS MajorVersion,
                  SUBSTRING_INDEX(SUBSTRING_INDEX("1.5.32",'.',-2),'.',1) AS MinorVersion,
                  SUBSTRING_INDEX("1.5.32",'.',-1) AS Revision;
                

                这将返回:

                MajorVersion | MinorVersion | Revision
                1            | 5            | 32
                

                【讨论】:

                  【解决方案15】:

                  好的,如果高性能是一个问题,那么您唯一的选择是将您的值更改为数字。

                  但是,如果这是一个使用率较低的查询,那么您可以将您的数字拆分并按这些查询排序。

                  此查询仅假定主要和次要版本号,并且它们仅包含数字。

                  SELECT
                      *
                  FROM
                      Requirements
                  WHERE
                      Requirements.Release NOT LIKE '%Obsolete%'
                  ORDER BY
                      CONVERT(int, RIGHT(REPLICATE('0', 10) + LEFT(Requirements.ReqNum, CHARINDEX('.', Requirements.ReqNum)-1), 10)),
                      CONVERT(int, SUBSTRING(Requirements.ReqNum, CHARINDEX('.', Requirements.ReqNum )+1, LEN(Requirements.ReqNum) - CHARINDEX('.', Requirements.ReqNum )))
                  

                  【讨论】:

                    【解决方案16】:

                    对于all-in-one-query purists,假设Oracle,一些instr/substr/decode/to_number voodoo 可以解决它:

                    SELECT *
                    FROM Requirements
                    WHERE Release NOT LIKE '%Obsolete%'
                    ORDER BY
                        to_number(
                          substr( reqnum, 1, instr( reqnum, '.' ) - 1 )
                        )
                      , to_number(
                          substr( 
                              reqnum
                            , instr( reqnum, '.' ) + 1 -- start: after first occurance
                            , decode( 
                                  instr( reqnum, '.', 1, 2 )
                                , 0, length( reqnum )
                                , instr( reqnum, '.', 1, 2 ) - 1 
                              ) -- second occurance (or end)
                              - instr( reqnum, '.', 1, 1) -- length: second occurance (or end) less first
                          )
                        )
                      , to_number(
                          decode( 
                              instr( reqnum, '.', 1, 2 )
                            , 0, null
                            , substr( 
                                  reqnum
                                , instr( reqnum, '.', 1, 2 ) + 1 -- start: after second occurance
                                , decode( 
                                      instr( reqnum, '.', 1, 3 )
                                    , 0, length( reqnum )
                                    , instr( reqnum, '.', 1, 3 ) - 1 
                                  ) -- third occurance (or end)
                                  - instr( reqnum, '.', 1, 2) -- length: third occurance (or end) less second
                              ) 
                          )
                        )
                      , to_number(
                          decode( 
                              instr( reqnum, '.', 1, 3 )
                            , 0, null
                            , substr( 
                                  reqnum
                                , instr( reqnum, '.', 1, 3 ) + 1 -- start: after second occurance
                                , decode( 
                                      instr( reqnum, '.', 1, 4 )
                                    , 0, length( reqnum )
                                    , instr( reqnum, '.', 1, 4 ) - 1 
                                  ) -- fourth occurance (or end)
                                  - instr( reqnum, '.', 1, 3) -- length: fourth occurance (or end) less third
                              ) 
                          )
                        )
                    ;
                    

                    我怀疑有很多警告,包括:

                    • 假设存在次要版本(第二个)
                    • 限于问题的 cmets 中指定的四个版本

                    【讨论】:

                      【解决方案17】:

                      这是一个用于 PostgreSQL 的比较函数,它将比较任意字符串,从而以数字方式比较数字序列。换句话说,“ABC123”>“ABC2”,但“AB123”

                      CREATE FUNCTION vercmp(a text, b text) RETURNS integer AS $$
                      DECLARE
                         ar text[];
                         br text[];
                         n integer := 1;
                      BEGIN
                         SELECT array_agg(y) INTO ar FROM (SELECT array_to_string(regexp_matches(a, E'\\d+|\\D+|^$', 'g'),'') y) x;
                         SELECT array_agg(y) INTO br FROM (SELECT array_to_string(regexp_matches(b, E'\\d+|\\D+|^$', 'g'),'') y) x;
                         WHILE n <= array_length(ar, 1) AND n <= array_length(br, 1) LOOP
                            IF ar[n] ~ E'^\\d+$' AND br[n] ~ E'^\\d+$' THEN
                               IF ar[n]::integer < br[n]::integer THEN
                                  RETURN -1;
                               ELSIF ar[n]::integer > br[n]::integer THEN
                                  RETURN 1;
                               END IF;
                            ELSE
                               IF ar[n] < br[n] THEN
                                  RETURN -1;
                               ELSIF ar[n] > br[n] THEN
                                  RETURN 1;
                               END IF;
                            END IF;
                            n := n + 1;
                         END LOOP;
                      
                         IF n > array_length(ar, 1) AND n > array_length(br, 1) THEN
                            RETURN 0;
                         ELSIF n > array_length(ar, 1) THEN
                            RETURN 1;
                         ELSE
                            RETURN -1;
                         END IF;
                      END;
                      $$ IMMUTABLE LANGUAGE plpgsql;
                      

                      然后您可以创建一个运算符类,以便通过使用ORDER BY field USING &lt;# 的比较函数来完成排序:

                      CREATE OR REPLACE FUNCTION vernum_lt(a text, b text) RETURNS boolean AS $$
                      BEGIN
                         RETURN vercmp(a, b) < 0;
                      END;
                      $$ IMMUTABLE LANGUAGE plpgsql;
                      
                      CREATE OR REPLACE FUNCTION vernum_lte(a text, b text) RETURNS boolean AS $$
                      BEGIN
                         RETURN vercmp(a, b) <= 0;
                      END;
                      $$ IMMUTABLE LANGUAGE plpgsql;
                      
                      CREATE OR REPLACE FUNCTION vernum_eq(a text, b text) RETURNS boolean AS $$
                      BEGIN
                         RETURN vercmp(a, b) = 0;
                      END;
                      $$ IMMUTABLE LANGUAGE plpgsql;
                      
                      CREATE OR REPLACE FUNCTION vernum_gt(a text, b text) RETURNS boolean AS $$
                      BEGIN
                         RETURN vercmp(a, b) > 0;
                      END;
                      $$ IMMUTABLE LANGUAGE plpgsql;
                      
                      CREATE OR REPLACE FUNCTION vernum_gte(a text, b text) RETURNS boolean AS $$
                      BEGIN
                         RETURN vercmp(a, b) >= 0;
                      END;
                      $$ IMMUTABLE LANGUAGE plpgsql;
                      
                      CREATE OPERATOR <# ( PROCEDURE = vernum_lt, LEFTARG = text, RIGHTARG = text);
                      CREATE OPERATOR ># ( PROCEDURE = vernum_gt, LEFTARG = text, RIGHTARG = text);
                      CREATE OPERATOR =# ( PROCEDURE = vernum_lte, LEFTARG = text, RIGHTARG = text);
                      CREATE OPERATOR <=# ( PROCEDURE = vernum_lte, LEFTARG = text, RIGHTARG = text);
                      CREATE OPERATOR >=# ( PROCEDURE = vernum_gte, LEFTARG = text, RIGHTARG = text);
                      
                      CREATE OPERATOR CLASS vernum_ops FOR TYPE varchar USING btree AS
                        OPERATOR 1 <# (text, text),
                        OPERATOR 2 <=# (text, text),
                        OPERATOR 3 =#(text, text),
                        OPERATOR 4 >=# (text, text),
                        OPERATOR 5 ># (text, text),
                        FUNCTION 1 vercmp(text, text)
                      ;
                      

                      【讨论】:

                        【解决方案18】:

                        以这种方式固定。

                        <pre>
                        00000001    1
                        00000001.00000001   1.1
                        00000001.00000001.00000001  1.1.1
                        00000001.00000002   1.2
                        00000001.00000009   1.9
                        00000001.00000010   1.10
                        00000001.00000011   1.11
                        00000001.00000012   1.12
                        00000002    2
                        00000002.00000001   2.1
                        00000002.00000001.00000001  2.1.1
                        00000002.00000002   2.2
                        00000002.00000009   2.9
                        00000002.00000010   2.10
                        00000002.00000011   2.11
                        00000002.00000012   2.12
                        
                        select * from (select '000000001' as tCode,'1' as Code union
                        select '000000001.000000001' as tCode,'1.1'as Code union
                        select '000000001.000000001.000000001' as tCode,'1.1.1'as Code union
                        select '000000001.000000002' as tCode,'1.2'  union
                        select '000000001.000000010' as tCode,'1.10'as Code union
                        select '000000001.000000011' as tCode,'1.11'as Code union
                        select '000000001.000000012' as tCode,'1.12'as Code union
                        select '000000001.000000009' as tCode,'1.9' as Code
                        union
                        select '00000002' as tCode,'2'as Code union
                        select '00000002.00000001' as tCode,'2.1'as Code union
                        select '00000002.00000001.00000001' as tCode,'2.1.1'as Code union
                        select '00000002.00000002' as tCode,'2.2'as Code union
                        select '00000002.00000010' as tCode,'2.10'as Code union
                        select '00000002.00000011' as tCode,'2.11'as Code union
                        select '00000002.00000012' as tCode,'2.12'as Code union
                        select '00000002.00000009' as tCode,'2.9'as Code ) as t
                        order by t.tCode
                        
                        </pre>
                        
                        <pre>
                        
                        
                        public static string GenerateToCodeOrder(this string code)
                            {
                                var splits = code.Split('.');
                                var codes = new List<string>();
                                foreach (var str in splits)
                                {
                                    var newStr = "";
                                    var zeroLength = 10 - str.Length;
                                    for (int i = 1; i < zeroLength; i++)
                                    {
                                        newStr += "0";
                                    }
                                    newStr += str;
                                    codes.Add(newStr);
                                }
                                return string.Join(".", codes);
                            }
                        
                        </pre>
                        

                        【讨论】:

                          【解决方案19】:

                          在 M$ SQL 中,我遇到了 hierachyid 的一些数据问题...

                          select Convert(hierarchyid, '/' + '8.3.0000.1088' + '/')
                          

                          为了解决这个问题,我使用了 pasename(依赖于 '.' 作为分隔符)...

                          Order by
                          convert(int, reverse (Parsename( reverse(tblSoftware.softwareVersion) , 1))),
                          convert(int, reverse (Parsename( reverse(tblSoftware.softwareVersion) , 2))),
                          convert(int, reverse (Parsename( reverse(tblSoftware.softwareVersion) , 3))),
                          convert(int, reverse (Parsename( reverse(tblSoftware.softwareVersion) , 4))),
                          convert(int, reverse (Parsename( reverse(tblSoftware.softwareVersion) , 5)))
                          

                          【讨论】:

                            【解决方案20】:

                            如果版本的列类型是 varchar,则排序按预期完成。 这是因为 varchar 没有用空格填充。

                            【讨论】:

                              【解决方案21】:

                              这是您可以在ORDER BY 中使用的 ORACLE 表达式:

                              select listagg(substr('0000000000' || column_value,-9), '.') within group(order by rownum) from xmltable(replace(version, '.',','))
                              

                              假设您的版本列只有点作为分隔符(任意数量的级别)。 (如果没有,由您来更改替换,例如 translate(version, '.-', ',,')

                              【讨论】:

                                【解决方案22】:

                                我会按照 Joel Coehoorn 所说的去做。然后重新排列您的数据结构,您不必手动进行。您可以编写一个简单的脚本来处理所有 600 条记录。

                                【讨论】:

                                • 为什么要添加与现有答案相同的答案?只需添加评论。
                                • 仅供参考,我想补充一点,他不必手动编辑所有记录,我发帖时还没有指出这一点。
                                【解决方案23】:

                                只需删除点(内联,替换为空字符串)将结果转换为intorder by 结果。效果很好:

                                a.Version = 1.4.18.14
                                
                                select...
                                Order by cast( replace (a.Version,'.','') as int) 
                                

                                【讨论】:

                                • 这根本不起作用。 1.0.1 会变成 101,2.0 会变成 20。101 肯定不会在 20 之前。OP 想要一种按分层版本排序的方法。
                                猜你喜欢
                                • 2015-06-29
                                • 1970-01-01
                                • 2011-04-06
                                • 2015-07-29
                                • 1970-01-01
                                • 2015-03-15
                                • 2016-02-04
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多