【问题标题】:mysql sorting of version numbersmysql版本号排序
【发布时间】:2011-11-22 10:13:24
【问题描述】:

我的价值观如下:

1.1.2 
9.1 
2.2
4
1.2.3.4
3.2.14
3.2.1.4.2
.....

我需要使用 mysql 对这些值进行排序。这个的数据类型是 varbinary(300)。

所需的输出将类似于:

1.1.2
1.2.3.4
2.2
3.2.1.4.2
3.2.14
4
9.1

查询是:

select version_number from table order by version_number asc 

它没有给出正确的排序顺序。

这个期望的输出是:

1.1.2
1.2.3.4
2.2
3.2.1.4.2
3.2.14 
4
9.1

版本号最多为 20 位(如 1.2.3.4.5.6.7.8.9.2.34),甚至更多。没有特定的最大尺寸,标准版本就像上面提到的那样。

【问题讨论】:

  • 您将这些存储为什么类型?
  • 按升序排列,您希望1.2.131.2.2 哪个最先出现?
  • 您能否发布您的输出并指出问题(实际与期望)?
  • 大多是把这个version_number存储在Varchar2中,所以不能像这样进行排序。
  • 每个组件是否有最大已知尺寸?您能否将标准化版本(例如 011.023.005 而不是 11.23.5)存储在单独的列中仅用于排序目的?

标签: mysql sorting


【解决方案1】:

尝试滥用INET_ATON 函数进行排序,如下所示:

SELECT version_number FROM table ORDER BY INET_ATON(SUBSTRING_INDEX(CONCAT(version_number,'.0.0.0'),'.',4))

这个技巧最初发布在mysql mailing list,非常感谢原始发布者Michael Stassen!

这是他要说的话:

如果每个部分不大于 255,你可以利用 INET_ATON() 来做 你想要什么(直到第 4 部分)。诀窍是使每一个 首先使用 CONCAT 添加“0.0.0”以确保每个 IP 看起来像一个 IP 行至少有 4 个部分,然后 SUBSTRING_INDEX 仅拉出 前 4 部分。

现在,我必须指出,因为我们正在对 列,而不是列本身,我们不能在 列来帮助排序。换句话说,排序将是 比较慢。

在后一种情况下,他推荐了一种类似于@spanky 发布的解决方案(单独的列)。

【讨论】:

    【解决方案2】:

    我会将它存储在三个单独的列中,版本号的每一部分各一列。

    将每列设为 TINYINT,甚至在 3 列之间创建索引。这应该让事情变得简单。

    然后你可以这样做: select CONCAT(v1,'.',v2,'.',v3) AS version_number FROM table ORDER BY v1 asc, v2 asc, v3 asc

    【讨论】:

    • 版本号中有 20 个组件,这将变得非常可怕。
    • 在这种情况下,您可以将您的版本复制为嵌套集模型,这样您就可以使其向各个方向增长,而无需向表中添加列。但实施这可能很麻烦。
    • 您可能还想考虑select concat('1', '.', '2', '.', null);,然后再考虑20列。
    • 是的,当我发布此问题时,问题不包括有 20 位数字的事实,而且看起来只有 3 或 4 位数字。似乎没有其他人发布答案。一方面,我想知道为什么有人会使用 20 个版本号。我什至无法想象一个场景。但为了提供帮助,我建议做一个固定宽度的标准化版本,如发布的@muistooshort。
    【解决方案3】:

    如果您想支持1.1-beta 之类的版本或使用没有INTE_ATON 的旧MySql 版本,您可以通过拆分版本并将每个部分排序为整数和字符串来获得相同的排序:

    SELECT
        version,
        REPLACE(SUBSTRING(SUBSTRING_INDEX(version, '.', 1), LENGTH(SUBSTRING_INDEX(version, '.', 1 - 1)) + 1), '.', '') v1,
        REPLACE(SUBSTRING(SUBSTRING_INDEX(version, '.', 2), LENGTH(SUBSTRING_INDEX(version, '.', 2 - 1)) + 1), '.', '') v2,
        REPLACE(SUBSTRING(SUBSTRING_INDEX(version, '.', 3), LENGTH(SUBSTRING_INDEX(version, '.', 3 - 1)) + 1), '.', '') v3,
        REPLACE(SUBSTRING(SUBSTRING_INDEX(version, '.', 4), LENGTH(SUBSTRING_INDEX(version, '.', 4 - 1)) + 1), '.', '') v4
    FROM 
        versions_table
    ORDER BY
        0+v1, v1 DESC, 0+v2, v2 DESC, 0+v3, v3 DESC, 0+v4, v4 DESC;
    

    【讨论】:

      【解决方案4】:

      使用正则表达式。首先对值进行归一化:

      SELECT REGEXP_REPLACE(
          REGEXP_REPLACE(
              REGEXP_REPLACE('v1.22.333', '^v', ''),
              '(^|\\.)(\\d+)',
              '\\100000\\2'
          ),
          '0+(\\d{5})(\\.|$)',
          '\\1\\2'
      )
      

      输出:

      00001.00022.00333
      

      然后就可以正常排序了。

      此解决方案适用于任意数量的组件。您可以将组件长度从 5 缩放到任何固定长度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多