【问题标题】:mysql order string as numbermysql订单字符串作为数字
【发布时间】:2012-12-05 17:52:20
【问题描述】:

我已经搜索了几天来在 mysql 中将字符串排序为数字。

我的行如下所示:

order_column

1.1.2
1.1.100
1.1.1

在mysql中按此列升序排列会产生:

1.1.1
1.1.100
1.1.2

我有兴趣得到以下结果:

1.1.1
1.1.2
1.1.100

有没有办法使用 SQL 产生这个结果?

我的专栏的其他可能值:

28.1999.1.1
1
1.1.154.20
100.1.1.1.1.15

谢谢,感谢大家的时间。

编辑: Fast Relational method of storing tree data (for instance threaded comments on articles) 看看第一个答案,Ayman Hourieh 的答案。我正在尝试使该解决方案发挥作用。我的网站每篇文章的 cmets 不超过 10k,所以我找到了这样的解决方法:

000001
000002
000002.000001
000002.000001.000001
000002.000002
000002.000003
000003

基本上,将零放在我的评论计数器之前,这样字符串比较就不会失败。但这仅适用于 99999 cmets。我可以添加更多的零,比如说 10 个零,这将适用于 999999999 cmets,但我希望有一个更优雅的解决方案。

【问题讨论】:

    标签: mysql string numbers


    【解决方案1】:

    如果字符串不是太长你可以这样做

    ORDER BY cast(replace(your_column_name,'.','') as unsigned);
    

    【讨论】:

    • 不错...但是如果列值像 1.2.1.1 和 1.1.1.100 那么我认为顺序将是错误的...
    • @mhasan:查询给出了问题中所述的所需输出:1.1.1 1.1.2,1.1.100。而且我不确定“1.2.1.1、1.1.1.100”的“正确”顺序是什么。在没有给出额外细节的情况下,我假设在删除“.”之后将字符串视为整数......
    • 如果有两个值:'28.1999.1.1'和'2819.99.1.1'怎么办?
    • @Devart : 删除 "." 后它们将是相同的,28199911 和 28199911。同样,没有给出任何要求,我不知道想要的行为是什么。
    • 我认为期望的行为是 28
    【解决方案2】:

    您将无法有效地执行此操作,因为这会丢失所有索引,但如果它是一次性的,这将起作用。遗憾的是,由于 MySQL 无法(据我所知)一次替换多个字符,因此它看起来很糟糕。

    SELECT value FROM TEST ORDER BY 
       REPLACE(
        REPLACE(
          REPLACE(
            REPLACE(
              REPLACE(
                REPLACE(
                  REPLACE(
                    REPLACE(
                      REPLACE(value, 
                        '1', '0'),
                      '2', '0'), 
                    '3', '0'), 
                  '4', '0'), 
                '5', '0'), 
              '6', '0'), 
            '7', '0'), 
          '8', '0'), 
        '9', '0'),value;
    

    它基本上会用 0 替换所有数字并首先按该顺序排序。由于. 在 0 之前排序,它会正确地按数字组排序。完成后,只需按值排序,因为具有相同数字组的任何值都应按正确顺序排序。

    为了提高效率,您可以将替换的值作为列存储在数据库中,以便您对其进行索引。

    SQLfiddle demo here.

    【讨论】:

      【解决方案3】:

      这不会是有效的,可以清理,但如何做到这一点的一个想法。它依赖于一个名为 integers 的表,其中包含一个名为 i 的单列,其中包含 10 行,值从 0 到 9。

      SELECT somefield    , SUM(POW(100, occurrences - anInteger) * somefield_split) OrderField
      FROM
          (SELECT id,anInteger,  somefield, SUBSTRING_INDEX(SUBSTRING_INDEX(somefield, ".", anInteger), ".", -1) AS somefield_split, LENGTH(somefield) - LENGTH(REPLACE(somefield, '.', '')) + 1 AS occurrences
          FROM splittertest, (SELECT a.i*10+b.i AS anInteger FROM integers a, integers b) Sub1
          HAVING occurrences >= anInteger) Sub2
      GROUP BY somefield
      ORDER BY somefield, OrderField
      

      想法是子选择获取从 0 到 99 的数字范围,并基于此将字符串拆分为点分隔值。它获取特定字符串中的点数。然后,它将字符串的每个位乘以 100 的部分总数减去该部分的数量的幂,并在此基础上求和。

      所以 5.10.15 被分成 5、10 和 15。有 3 个部分,所以第一个部分乘以 100 的 (3 - 0) 次方,第二个部分乘以 100 的 (2 - 0) 次方) 等。

      如果点数变化,这确实会产生奇怪的结果(即,点数越多的点总是越大),但这可以通过在计算功率时使用任何线上的最大点数来解决,而不是比该特定行上的点数。

      祝你好运!

      【讨论】:

        【解决方案4】:
        SELECT INET_ATON('10.0.5.9');
        

        试试你的这个功能:)

        也许这不是替代方案,因为它仅适用于 IP 地址类型。而且您确实拥有比 IP 地址更多的部分。

        【讨论】:

        • 这是否适用于不是 IP 地址的字符串?给出的例子不是。
        • @Cylindric 是的,刚刚注意到 ;) 我希望我们在 IP 地址排序之外还有这样的功能
        【解决方案5】:

        创建一个与此列相等的新列,并将字符串替换为 '.'用''(什么都没有)。将此新字段存储为数字。在您的查询中按此字段排序。

        如果您无法在表格中添加新列,您可以在 PHP 等中进行处理,以达到相同的效果,例如在网站上显示。

        http://php.net/manual/en/function.str-replace.php
        

        【讨论】:

        • 如果我替换 '.'如果什么都没有,那么 1.11 将等于 11.1 和 1.1.1
        • 好的,您可以将 1.1.1 拆分为三列,然后您需要按列 1、2、3 排序并在语句中使用 group by。
        【解决方案6】:

        确保这些数字的列是 INT 而不是 varchar。

        如果您使用 varchar,您的列将按第一个为 1 的人排序,依此类推...

        【讨论】:

        • 不要做任何额外的代码,按照我告诉你的去做,将这些数字的列更改为 INT 而不是 char 或 varchar
        【解决方案7】:

        可以使用下面的sql

        SELECT REPLACE(column_name,'.','') AS column_name1 FROM table_name ORDER BY column_name1;
        

        【讨论】:

          【解决方案8】:

          如果您按最后一位数字组排序,那么

          SELECT CAST(MID(order_column, 
          CHAR_LENGTH(order_column) - 
          LOCATE('.',REVERSE(order_column))+2) AS DECIMAL) AS order_column_as_number
          FROM thetable 
          ORDER BY order_column_as_number
          

          似乎有效。

          如果有没有'.'的字符串则根本不起作用如果您还想按其他组订购,则必须提取更多零件进行订购,但如果您真的希望仅在 sql 中完成,这可能是一个开始。

          【讨论】:

          • 这不仅仅是最后一个数字组。它看起来更像是“按第一组、第二组、第三组排序”等。
          • 对于不包含“.”的示例也失败了。我想通过这种方式可以提取更多的东西来订购,但它很快就会变得一团糟。
          【解决方案9】:

          这是我对最多 4 位小数的数字的解决方案:

          SELECT myCol, SUBSTRING_INDEX(myCol, ',', 1) * 10000 + LEFT(CONCAT(SUBSTRING_INDEX(myCol, ',', -1), '0000'), 4) as toOrder 
          FROM `myTable`
          ORDER BY toOrder DESC
          

          您可以像这样设置 8 位小数:

          SELECT myCol, SUBSTRING_INDEX(myCol, ',', 1) * 100000000 + LEFT(CONCAT(SUBSTRING_INDEX(myCol, ',', -1), '00000000'), 8) as toOrder 
          FROM `myTable`
          ORDER BY toOrder DESC
          

          等等……

          【讨论】:

            【解决方案10】:

            先按INSTR排序,再用“.”排序

            SELECT content_id FROM TEST ORDER BY INSTR(`content_id`, '.'), replace(`content_id`,'.','')
            

            SQLfiddle

            【讨论】:

              猜你喜欢
              • 2012-08-02
              • 2019-08-20
              • 1970-01-01
              • 1970-01-01
              • 2012-08-18
              • 2019-11-09
              • 2021-11-22
              • 2013-07-29
              • 2011-06-16
              相关资源
              最近更新 更多