【问题标题】:Sorting string column containing numbers in SQL?在SQL中对包含数字的字符串列进行排序?
【发布时间】:2011-02-08 23:00:42
【问题描述】:

我正在尝试对字符串列进行排序(包含数字)。

// SELECT `name` FROM `mytable` ORDER BY `name` ASC
+----------+
+-- name --+
+----------+
+-- a 1 ---+
+-- a 12 --+
+-- a 2 ---+
+-- a 3 ---+

你看到 Mysql 的自然排序算法是把 a 12 放在 a 1 之后(这对大多数应用程序来说都可以),但我有独特的需求,所以我希望结果应该像这样排序.

+----------+
+-- name --+
+----------+
+-- a 1 ---+
+-- a 2 ---+
+-- a 3 ---+
+-- a 12 --+

是否可以仅使用 SQL,或者我必须在应用程序级别操作结果集?

【问题讨论】:

  • 所有行的字母前缀是否总是固定长度?
  • 不,这是一个经常重复的常规字符串。
  • 那么像order by left(name,1), cast(SUBSTRING(name,2) as int) 这样的东西就行不通了。您能否提供一些更多样化的数据来说明您的确切需求?
  • @Martin MySQL 强制转换不适用于 int 必须使用 signed .... 但即使您的评论是 very precious ... 因为您对两个子字符串使用了双重排序.
  • 替代解决方案:SELECT * FROM mytable ORDER BY length(name), name; 性能好 :)

标签: sql mysql sql-order-by


【解决方案1】:

继续假设它总是 WORD_space_NUMBER 这应该可以工作:

SELECT   *
FROM     table
ORDER BY CAST(SUBSTRING(column,LOCATE(' ',column)+1) AS SIGNED)

使用POSITION 查找空格,SUBSTRING 获取其后的数字,使用CAST 使其具有可比性。

如果该列有不同的模式,请告诉我,我会尝试设计一个更好的解决方法。


编辑证明有效:

mysql> INSERT INTO t (st) VALUES ('a 1'),('a 12'),('a 6'),('a 11');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t ORDER BY st;
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  4 | a 11 |
|  2 | a 12 |
|  3 | a 6  |
+----+------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM t ORDER BY CAST(SUBSTRING(st,LOCATE(' ',st)+1) AS SIGNED);
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  3 | a 6  |
|  4 | a 11 |
|  2 | a 12 |
+----+------+

mysql> INSERT INTO t (st) VALUES ('b 1'),('b 12'),('b 6'),('b 11');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t ORDER BY CAST(SUBSTRING(st,LOCATE(' ',st)+1) AS SIGNED);
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  5 | b 1  |
|  3 | a 6  |
|  7 | b 6  |
|  4 | a 11 |
|  8 | b 11 |
|  2 | a 12 |
|  6 | b 12 |
+----+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM t ORDER BY LEFT(st,LOCATE(' ',st)), CAST(SUBSTRING(st,LOCATE(' ',st)+1) AS SIGNED);
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  3 | a 6  |
|  4 | a 11 |
|  2 | a 12 |
|  5 | b 1  |
|  7 | b 6  |
|  8 | b 11 |
|  6 | b 12 |
+----+------+
8 rows in set (0.00 sec)

忽略我蹩脚的表/列名,但给了我正确的结果。还更进一步,添加了双重排序来用数字打破字母前缀。

编辑 SUBSTRING_INDEX 会使其更具可读性。

ORDER BY SUBSTRING_INDEX(st, " ", 1) ASC, CAST(SUBSTRING_INDEX(st, " ", -1) AS SIGNED)

【讨论】:

  • @ish:没问题。您还可以在 order by 中添加LEFT(column,LOCATE(' ',column)),以先按字母分组,然后按数字分组。
  • 感谢您提供更多选择 :),您的原始解决方案符合我的目的。我了解了 MySQL 的 CAST 能力......干杯
【解决方案2】:

你可以试试这个:

ORDER BY CASE
  WHEN ISNUMERIC(column) THEN cast(column as int) 
  else ascii(column[1,1]) 
end

【讨论】:

    【解决方案3】:

    看看 MySQL CAST / Convert 函数。

    SELECT name FROM mytable ORDER BY CAST(name AS INTEGER) ASC;
    

    编辑: 我读到:

    我正在尝试对字符串列进行排序 (包含数字)。

    ...但只是看看结果集。 a 实际上也是内容的一部分吗?如果是这样,您可以使用 MID 之类的函数仅提取数值并进行转换。

    但如果所有行只包含a而没有变化,你不妨省略它...

    【讨论】:

    • 得到mysql错误right syntax to use near 'INTEGER) ASC LIMIT 0, 30
    • @Ish:由于同样的事情我忘记了。使用 CAST/CONVERT 时必须使用 SIGNED/UNSIGNED。
    【解决方案4】:

    另一种选择是在数字左侧用空格填充字符串(即在单词和数字之间添加空格)并使用生成的字符串进行排序,如下所示:

    ORDER BY INSERT(
      column,
      LOCATE(' ', column),
      0,
      SPACES(20 - LENGTH(column) + LOCATE(' ', column))
    )
    

    字符串被假定为“单词后跟空格后跟数字”的模式,并且数字被假定为非负数(否则会错误排序)。硬编码的20 是任意选择的,应该是字符串的数字部分的最大可能长度。

    【讨论】:

      【解决方案5】:

      在这里我找到了另一个解决方案,使用 Convert 进行以下查询

      select * from tablename where columnname like '%a%' order by Convert(smallint,Replace(columnname,'a',''))
      

      【讨论】:

        猜你喜欢
        • 2021-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-11
        • 2020-05-14
        • 2017-08-11
        • 2021-02-22
        • 2021-08-02
        相关资源
        最近更新 更多