【问题标题】:SQL order string as numberSQL 订单字符串作为数字
【发布时间】:2012-08-02 06:15:30
【问题描述】:

我将数字保存为VARCHAR 到 MySQL 数据库。由于其他一些情况,我不能让他们INT

排序时将它们视为字符而不是数字。

在数据库中我有

1 2 3 4 5 6 7 8 9 10...

在我的页面上,它显示了这样的有序列表:

1 10 2 3 4 5 6 7 8 9

如何让它显示为按数字升序排列?

【问题讨论】:

标签: mysql sql string numbers sql-order-by


【解决方案1】:

如果您使用的是 AdonisJS 并且具有混合 ID,例如 ABC-202、ABC-201...,您可以将原始查询与 Query Builder 结合起来,并按如下方式实现上述解决方案 (https://stackoverflow.com/a/25061144/4040835):

const sortField =
  'membership_id'
const sortDirection =
  'asc'
const subquery = UserProfile.query()
  .select(
    'user_profiles.id',
    'user_profiles.user_id',
    'user_profiles.membership_id',
    'user_profiles.first_name',
    'user_profiles.middle_name',
    'user_profiles.last_name',
    'user_profiles.mobile_number',
    'countries.citizenship',
    'states.name as state_of_origin',
    'user_profiles.gender',
    'user_profiles.created_at',
    'user_profiles.updated_at'
  )
  .leftJoin(
    'users',
    'user_profiles.user_id',
    'users.id'
  )
  .leftJoin(
    'countries',
    'user_profiles.nationality',
    'countries.id'
  )
  .leftJoin(
    'states',
    'user_profiles.state_of_origin',
    'states.id'
  )
  .orderByRaw(
    `SUBSTRING(:sortField:,3,15)*1 ${sortDirection}`,
    {
      sortField: sortField,
    }
  )
  .paginate(
    page,
    per_page
  )

注意事项: 在这一行:SUBSTRING(:sortField:,3,15)*1 ${sortDirection},

  1. '3' 代表数字前最后一个非数字字符的索引号。如果您的混合 ID 是“ABC-123”,那么您的索引号将为 4。
  2. '15' 用于在连字符后捕获尽可能多的数字。
  3. '1' 对子字符串执行数学运算,有效地将子字符串转换为数字。

参考 1:您可以在此处阅读有关原始查询中的参数绑定的更多信息:https://knexjs.org/#Raw-Bindings 参考 2:Adonis 原始查询:https://adonisjs.com/docs/4.1/query-builder#_raw_queries

【讨论】:

    【解决方案2】:

    这可能会对正在寻找相同解决方案的人有所帮助。

    select * from tablename ORDER BY ABS(column_name)
    

    【讨论】:

      【解决方案3】:

      这将处理负数、分数、字符串,一切:

      ORDER BY ISNUMERIC(col) DESC, Try_Parse(col AS decimal(10,2)), col;
      

      【讨论】:

        【解决方案4】:

        如果您只存储数字,则应尽可能将列的数据类型更改为数字。

        如果你不能这样做,那么将你的列值转换为integer 显式 with

        select col from yourtable
        order by cast(col as unsigned)
        

        隐式,例如使用强制转换为数字的数学运算

        select col from yourtable
        order by col + 0
        

        顺便说一句,MySQL 从左到右转换字符串。例子:

        string value  |  integer value after conversion
        --------------+--------------------------------
        '1'           |  1
        'ABC'         |  0   /* the string does not contain a number, so the result is 0 */
        '123miles'    |  123 
        '$123'        |  0   /* the left side of the string does not start with a number */
        

        【讨论】:

        • 按 col * 1 排序完美。这背后有什么魔力?抱歉,我不是专业人士,所以这可能是个愚蠢的问题,但是 *1 如何使它变为数字?
        • MySQL 自动将字符串转换为数字与1相乘
        • 第一个选项是最合适的一个,第二个有一个额外的步骤,但它的工作原理不会少。
        • 如果你有混合的字符串和数字并希望它们都排序,使用“order by col * 1, col”
        • @superphonic:结果将是decimal
        【解决方案5】:

        另一种方式,不使用单个演员表。

        (对于使用 JPA 2.0 的人,不允许强制转换)

        select col from yourtable
        order by length(col),col
        

        编辑:仅适用于正整数

        【讨论】:

        • 这是一个很好的方法,它适用于同时包含 int 和 string 的列
        • 这并不适用于所有情况。在头顶上,不起作用的案例是整数的混合;负数、带前导零的数字、带分数的数字以及单词和数字的组合。
        • 很好的解决方案,没有任何铸造和杂耍类型,+1
        • 乍一看似乎不起作用,但它起作用了!谢谢!
        • 这种排序如何指定 asc 或 desc 顺序?
        【解决方案6】:

        这对我有用。

        select * from tablename
        order by cast(columnname as int) asc
        

        【讨论】:

        • 你能解释一下为什么吗?
        • 最简单的答案,正是需要的,将字符串转换为 int ,然后按该 int 升序排序,没有时髦的东西 :)
        【解决方案7】:

        另一种简单的方法

        ORDER BY ABS(column_name)

        【讨论】:

          【解决方案8】:

          我也在寻找一个带有字母前缀的排序字段。这是我找到的解决方案。这可能会对正在寻找相同解决方案的人有所帮助。

          字段值:

          FL01,FL02,FL03,FL04,FL05,...FL100,...FL123456789
          
          select SUBSTRING(field,3,9) as field from table order by SUBSTRING(field,3,10)*1 desc
          

          SUBSTRING(field,3,9) 我放了 9,因为 9 足以让我保存最多 9 位整数值。

          所以结果将是 123456789 123456788 123456787 ... 100 99 ... 2 1

          【讨论】:

            【解决方案9】:

            将您的字段更改为 INT 而不是 VARCHAR。

            由于其他一些情况,我无法将它们设为 INT。

            然后先解决依赖的情况。否则,您正在解决真正的潜在问题。使用 MySQL CAST 是一种选择,但它掩盖了应该修复的错误模式。

            【讨论】:

              【解决方案10】:

              我用来排序的列可以是字母和数字的任意组合,所以我使用这篇文章中的建议作为起点并想出了这个。

              DECLARE @tmp TABLE (ID VARCHAR(50));
              INSERT INTO @tmp VALUES ('XYZ300');
              INSERT INTO @tmp VALUES ('XYZ1002');
              INSERT INTO @tmp VALUES ('106');
              INSERT INTO @tmp VALUES ('206');
              INSERT INTO @tmp VALUES ('1002');
              INSERT INTO @tmp VALUES ('J206');
              INSERT INTO @tmp VALUES ('J1002');
              
              SELECT ID, (CASE WHEN ISNUMERIC(ID) = 1 THEN 0 ELSE 1 END) IsNum
              FROM @tmp
              ORDER BY IsNum, LEN(ID), ID;
              

              结果

              ID
              ------------------------
              106
              206
              1002
              J206
              J1002
              XYZ300
              XYZ1002
              

              希望对你有帮助

              【讨论】:

              • 您可以简单地使用1 - ISNUMERIC(ID) 而不是(CASE WHEN ISNUMERIC(ID) = 1 THEN 0 ELSE 1 END) 将0 更改为1,反之亦然。
              【解决方案11】:

              另一种转换方式。

              如果您有字符串字段,您可以通过以下方式对其或其数字部分进行转换:添加前导零以使所有整数字符串具有相等的长度。

              ORDER BY CONCAT( REPEAT(  "0", 18 - LENGTH( stringfield ) ) , stringfield ) 
              

              或按字段的一部分排序,例如“tensymbols13”、“tensymbols1222”等。

              ORDER BY CONCAT( REPEAT(  "0", 18 - LENGTH( LEFT( stringfield , 10 ) ) ) , LEFT( stringfield , 10 ) ) 
              

              【讨论】:

                猜你喜欢
                • 2012-12-05
                • 1970-01-01
                • 2019-08-20
                • 2014-12-13
                • 1970-01-01
                • 2019-11-09
                • 1970-01-01
                • 2018-06-22
                • 2015-11-27
                相关资源
                最近更新 更多