MySQL 'Order By' - 正确排序字母数字

Posted

技术标签:

【中文标题】MySQL \'Order By\' - 正确排序字母数字【英文标题】:MySQL 'Order By' - sorting alphanumeric correctlyMySQL 'Order By' - 正确排序字母数字 【发布时间】:2012-01-23 08:06:25 【问题描述】:

我想按照下面显示的顺序(数字 1-12)对以下数据项进行排序:

1 2 3 4 5 6 7 8 9 10 11 12

但是,我的查询 - 使用 order by xxxxx asc 按第一位数字排序:

1 10 11 12 2 3 4 5 6 7 8 9

有什么技巧可以让它更正确地排序?

此外,为了全面披露,这可能是字母和数字的混合(虽然现在不是),例如:

A1 534G G46A 100B 100A 100JE

等等……

谢谢!

更新:人们要求查询

select * from table order by name asc

【问题讨论】:

相关:***.com/questions/48600059/… 【参考方案1】:

人们使用不同的技巧来做到这一点。我用谷歌搜索了一些结果,每个结果都遵循不同的技巧。看看他们:

Alpha Numeric Sorting in mysql Natural Sorting in MySQL Sorting of numeric values mixed with alphanumeric values mySQL natural sort Natural Sort in MySQL

编辑:

我刚刚为未来的访问者添加了每个链接的代码。

Alpha Numeric Sorting in MySQL

给定输入

1A 1a 10A 9B 21C 1C 1D

预期输出

1A 1C 1D 1a 9B 10A 21C

查询

Bin Way
===================================
SELECT 
tbl_column, 
BIN(tbl_column) AS binray_not_needed_column
FROM db_table
ORDER BY binray_not_needed_column ASC , tbl_column ASC

-----------------------

Cast Way
===================================
SELECT 
tbl_column, 
CAST(tbl_column as SIGNED) AS casted_column
FROM db_table
ORDER BY casted_column ASC , tbl_column ASC

Natural Sorting in MySQL

给定输入

表:sorting_test
 -------------- -------------
|字母数字 VARCHAR(75) |整数 INT |
 -------------- -------------
|测试1 | 1 |
|测试12 | 2 |
|测试13 | 3 |
|测试2 | 4 |
|测试3 | 5 |
 -------------- -------------

预期输出

 -------------------------- -------------
| alphanumeric VARCHAR(75) | integer INT |
 -------------------------- -------------
| test1                    | 1           |
| test2                    | 4           |
| test3                    | 5           |
| test12                   | 2           |
| test13                   | 3           |
 -------------------------- -------------

查询

SELECT alphanumeric, integer
       FROM sorting_test
       ORDER BY LENGTH(alphanumeric), alphanumeric  

Sorting of numeric values mixed with alphanumeric values

给定输入

2a, 12, 5b, 5a, 10, 11, 1, 4b

预期输出

1, 2a, 4b, 5a, 5b, 10, 11, 12

查询

SELECT version
FROM version_sorting
ORDER BY CAST(version AS UNSIGNED), version;

希望对你有帮助

【讨论】:

在这篇文章中包含更完整的信息会很棒。 @showdev 我已经包含了它,希望它可能会有所帮助:) 这些都不适合我:/对这样的列表有什么建议吗? pastebin.com/d4kXq6HS 理想输出为:pastebin.com/kJ4Zc3XY 如果输入是 A1, A10, B1, C11, D8 怎么办?任何技巧都不起作用 我刚刚为 MySQL 发布了一个真实的、通用的 nat-sort 函数,它应该正确处理所有示例,除此之外还有更多。在此处查看我对“MySQL 中的自然排序”的回答:***.com/a/58154535/999120【参考方案2】:

这样做:

SELECT * FROM table ORDER BY column `name`+0 ASC

附加 +0 意味着:

0, 10, 11, 2、 3、 4

变成:

0, 2、 3、 4、 10, 11

【讨论】:

这非常危险!在我的查询中它运行良好,我赞成答案但是当我刷新时,它没有用!然后我继续刷新查询 100 次,它随机工作并且不适用于相同的查询!不要依赖这个!我的表末尾有一个数字,这是我的查询:SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'my_database' AND TABLE_NAME LIKE '%my_table%' ORDER BY TABLE_NAME+0 DESC LIMIT 1 @Tarik 这可能是因为您使用的information_schema 只是估计值,它们没有完全汇总。 @Andrew Odendaal 的答案每次都对我有用 ORDER BY 'name'+0 ASC【参考方案3】:

我知道这篇文章已关闭,但我认为我的方式可以帮助一些人。就是这样:

我的数据集非常相似,但有点复杂。它有数字、字母数字数据:

1
2
Chair 
3
0
4
5
-
Table
10
13
19
Windows
99
102
Dog

我想先有“-”符号,然后是数字,然后是文本。

所以我就这样走了:

SELECT name, (name = '-') boolDash, (name = '0') boolZero, (name+0 > 0) boolNum 
FROM table 
ORDER BY boolDash DESC, boolZero DESC, boolNum DESC, (name+0), name

结果应该是这样的:

-
0    
1
2
3
4
5
10
13
99
102
Chair
Dog
Table
Windows

整个想法是对 SELECT 进行一些简单的检查并根据结果进行排序。

【讨论】:

我无法通过将 (name = '-') boolDash 放在 select 语句中来实现这一点。但是我通过将name = '-' 直接放在 order by 语句中来使其工作。【参考方案4】:

我讨厌这个,但this 会起作用

order by lpad(name, 10, 0)  <-- assuming maximum string length is 10
                            <-- you can adjust to a bigger length if you want to

【讨论】:

这实际上适用于我的USA-0027-1,USA-0027-2,USA-0027-10,USA-0027-12场景 这对我有用,也谢谢你拯救了我的另一天。 也适合我。这是我最喜欢的解决方案。非常感谢!【参考方案5】:

这适用于数据类型: 数据1, 数据2,数据3 ......,数据21。表示“数据”字符串在所有行中都是通用的。

对于 ORDER BY ASC 它将完美排序,对于 ORDER BY DESC 不合适。

SELECT * FROM table_name ORDER BY LENGTH(column_name), column_name ASC;

【讨论】:

ALTER TABLE 的类似查询会是什么??【参考方案6】:

我用

取得了一些不错的成绩
SELECT alphanumeric, integer FROM sorting_test ORDER BY CAST(alphanumeric AS UNSIGNED), alphanumeric ASC

【讨论】:

【参考方案7】:

此类问题之前已提出。

您所说的排序类型称为“自然排序”。 您要对其进行排序的数据是字母数字的。 最好创建一个新列进行排序。

如需进一步帮助,请查看 natural-sort-in-mysql

【讨论】:

【参考方案8】:

如果您需要对没有任何标准格式的字母数字列进行排序

SELECT * FROM table ORDER BY (name = '0') DESC, (name+0 > 0) DESC, name+0 ASC, name ASC

如果需要,您可以使用其他逻辑调整此解决方案以包括对非字母数字字符的支持。

【讨论】:

这是唯一适用于整个互联网的解决方案【参考方案9】:

这应该对字母数字字段进行排序,例如: 1/ 仅数字,order by 1,2,3,4,5,6,7,8,9,10,11 等... 2/ 然后字段的文本如下:1foo, 2bar, aaa11aa, aaa22aa, b5452 等...

SELECT  MyField
FROM MyTable
order by 
    IF( MyField REGEXP '^-?[0-9]+$' = 0, 
    9999999999 ,  
    CAST(MyField AS DECIMAL) 
    ), MyField

查询检查数据是否为数字,如果不是则放入 9999999999 ,则先对该列排序,再对文本数据排序

祝你好运!

【讨论】:

【参考方案10】:

我没有尝试编写一些函数并减慢SELECT 查询的速度,而是想到了另一种方法......

在您的数据库中创建一个额外的字段来保存以下类的结果,当您插入新行时,运行将通过该类自然排序的字段值并将其结果保存在额外的字段中。然后,不要按原始字段排序,而是按额外字段排序。

String nsFieldVal = new NaturalSortString(getFieldValue(), 4).toString()

The above means:
- Create a NaturalSortString for the String returned from getFieldValue()
- Allow up to 4 bytes to store each character or number (4 bytes = ffff = 65535)

| field(32)  |  nsfield(161)                            |   
  a1            300610001

String sortString = new NaturalSortString(getString(), 4).toString()

import StringUtils;

/**
 * Creates a string that allows natural sorting in a SQL database
 * eg, 0 1 1a 2 3 3a 10 100 a a1 a1a1 b
 */
public class NaturalSortString 

    private String inStr;
    private int byteSize;
    private StringBuilder out = new StringBuilder();

    /**
     * A byte stores the hex value (0 to f) of a letter or number.
     * Since a letter is two bytes, the minimum byteSize is 2.
     *
     * 2 bytes = 00 - ff  (max number is 255)
     * 3 bytes = 000 - fff (max number is 4095)
     * 4 bytes = 0000 - ffff (max number is 65535)
     *
     * For example:
     * dog123 = 64,6F,67,7B and thus byteSize >= 2.      
     * dog280 = 64,6F,67,118 and thus byteSize >= 3.
     *
     * For example:
     * The String, "There are 1000000 spots on a dalmatian" would require a byteSize that can 
     * store the number '1000000' which in hex is 'f4240' and thus the byteSize must be at least 5
     *
     * The dbColumn size to store the NaturalSortString is calculated as:
     * > originalStringColumnSize x byteSize + 1
     * The extra '1' is a marker for String type - Letter, Number, Symbol
     * Thus, if the originalStringColumn is varchar(32) and the byteSize is 5:
     * > NaturalSortStringColumnSize = 32 x 5 + 1 = varchar(161)
     *
     * The byteSize must be the same for all NaturalSortStrings created in the same table.
     * If you need to change the byteSize (for instance, to accommodate larger numbers), you will
     * need to recalculate the NaturalSortString for each existing row using the new byteSize.
     *
     * @param str        String to create a natural sort string from
     * @param byteSize   Per character storage byte size (minimum 2)
     * @throws Exception See the error description thrown
     */
    public NaturalSortString(String str, int byteSize) throws Exception 
        if (str == null || str.isEmpty()) return;
        this.inStr = str;
        this.byteSize = Math.max(2, byteSize);  // minimum of 2 bytes to hold a character
        setStringType();
        iterateString();
    

    private void setStringType() 
        char firstchar = inStr.toLowerCase().subSequence(0, 1).charAt(0);
        if (Character.isLetter(firstchar))     // letters third
            out.append(3);
        else if (Character.isDigit(firstchar)) // numbers second
            out.append(2);
        else                                   // non-alphanumeric first
            out.append(1);
    

    private void iterateString() throws Exception 
        StringBuilder n = new StringBuilder();
        for (char c : inStr.toLowerCase().toCharArray())  // lowercase for CASE INSENSITIVE sorting
            if (Character.isDigit(c)) 
                // group numbers
                n.append(c);
                continue;
            
            if (n.length() > 0) 
                addInteger(n.toString());
                n = new StringBuilder();
            
            addCharacter(c);
        
        if (n.length() > 0) 
            addInteger(n.toString());
        
    

    private void addInteger(String s) throws Exception 
        int i = Integer.parseInt(s);
        if (i >= (Math.pow(16, byteSize)))
            throw new Exception("naturalsort_bytesize_exceeded");
        out.append(StringUtils.padLeft(Integer.toHexString(i), byteSize));
    

    private void addCharacter(char c) 
        //TODO: Add rest of accented characters
        if (c >= 224 && c <= 229) // set accented a to a
            c = 'a';
        else if (c >= 232 && c <= 235) // set accented e to e
            c = 'e';
        else if (c >= 236 && c <= 239) // set accented i to i
            c = 'i';
        else if (c >= 242 && c <= 246) // set accented o to o
            c = 'o';
        else if (c >= 249 && c <= 252) // set accented u to u
            c = 'u';
        else if (c >= 253 && c <= 255) // set accented y to y
            c = 'y';

        out.append(StringUtils.padLeft(Integer.toHexString(c), byteSize));
    

    @Override
    public String toString() 
        return out.toString();
    

为了完整起见,下面是StringUtils.padLeft 方法:

public static String padLeft(String s, int n) 
    if (n - s.length() == 0) return s;
    return String.format("%0" + (n - s.length()) + "d%s", 0, s);

结果应该如下所示

-1
-a
0
1
1.0
1.01
1.1.1
1a
1b
9
10
10a
10ab
11
12
12abcd
100
a
a1a1
a1a2
a-1
a-2
áviacion
b
c1
c2
c12
c100
d
d1.1.1
e

【讨论】:

确实,在 MySQL 中进行 nat-sort 的最佳方法是根据单独的排序键进行排序。但是,您的解决方案 (a) 需要 MySQL 外部的代码来创建这些键,(b) 在对文本部分进行排序时忽略排序规则,(c) 在排序键表示方面非常效率低下, (d) 与简单地将字符串中的所有数字左填充到固定字符长度相比,绝对没有优势(就像***.com/q/153633/999120 页面上的其他几个解决方案一样)。抱歉,但这个答案太可怕了:被否决了。【参考方案11】:

MySQL ORDER BY 按正确顺序对字母数字进行排序

示例:

SELECT `alphanumericCol` FROM `tableName` ORDER BY 
  SUBSTR(`alphanumericCol` FROM 1 FOR 1), 
  LPAD(lower(`alphanumericCol`), 10,0) ASC

输出:

1
2
11
21
100
101
102
104
S-104A
S-105
S-107
S-111

【讨论】:

【参考方案12】:

这是教程点

SELECT * FROM yourTableName ORDER BY
SUBSTR(yourColumnName FROM 1 FOR 2),
CAST(SUBSTR(yourColumnName FROM 2) AS UNSIGNED);

与本帖的另一个回答略有不同

供参考,这是原始链接 https://www.tutorialspoint.com/mysql-order-by-string-with-numbers

关于 UNSIGNED 的另一点写在这里 https://electrictoolbox.com/mysql-order-string-as-int/

虽然这也有 REGEX https://www.sitepoint.com/community/t/how-to-sort-text-with-numbers-with-sql/346088/9

【讨论】:

【参考方案13】:
SELECT length(actual_project_name),actual_project_name,
SUBSTRING_INDEX(actual_project_name,'-',1) as aaaaaa,
SUBSTRING_INDEX(actual_project_name, '-', -1) as actual_project_number,
concat(SUBSTRING_INDEX(actual_project_name,'-',1),SUBSTRING_INDEX(actual_project_name, '-', -1)) as a
FROM ctts.test22 
order by 
SUBSTRING_INDEX(actual_project_name,'-',1) asc,cast(SUBSTRING_INDEX(actual_project_name, '-', -1) as unsigned) asc

【讨论】:

当我们使用 LENGTH(column_name) 时,column_name ASC 根据长度函数值进行排序。如果长度不同,则排序不起作用。使用上面的查询。【参考方案14】:

这是一个简单的例子。

SELECT HEX(some_col) h        
FROM some_table 
ORDER BY h

【讨论】:

【参考方案15】:

对我的场景来说真的有问题......

select * from table order by lpad(column, 20, 0)

我的列是 varchar,但有数字输入 (1, 2, 3...) ,混合数字 (1A, 1B, 1C) 和字符串数据 (INT, SHIP)

【讨论】:

【参考方案16】:

按顺序试试这个

SELECT * FROM testdata ORDER BY LENGHT(name) DESC, name DESC

【讨论】:

【参考方案17】:
SELECT 
s.id, s.name,  LENGTH(s.name) len, ASCII(s.name) ASCCCI
FROM table_name s
ORDER BY ASCCCI,len,NAME ASC;

【讨论】:

【参考方案18】:

假设varchar字段包含数字、十进制、字母数字和字符串,例如:

Let's suppose Column Name is "RandomValues" and Table name is "SortingTest" 

A1
120
2.23
3
0
2
Apple
Zebra
Banana 
23
86.Akjf9
Abtuo332
66.9
22
ABC

SELECT * FROM SortingTest 按 IF 排序(RandomValues REGEXP '^-?[0-9,.]+$' = 0, 9999999999 , CAST(RandomValues十进制) ), RandomValues

Above query will do sorting on number & decimal values first and after that all alphanumeric values got sorted. 

【讨论】:

【参考方案19】:

这将始终将值以数字开头:

ORDER BY my_column REGEXP '^[0-9]' DESC, length(my_column  + 0), my_column ";

工作如下:

Step1 - 第一个字符是数字吗? 1 为真,0 为假,按此 DESC 排序 Step2 - 数字是多少位?按此 ASC 订购 第 3 步 - 按字段本身排序

输入:

  ('100'),
  ('1'),
  ('10'),
  ('0'),
  ('2'),
  ('2a'),
  ('12sdfa'),
  ('12 sdfa'),
  ('Bar nah');

输出:

0
1
2
2a
10
12 sdfa
12sdfa
100
Bar nah

【讨论】:

以上是关于MySQL 'Order By' - 正确排序字母数字的主要内容,如果未能解决你的问题,请参考以下文章

MySQL order by - 排序不正确

MySQL ORDER BY 偏移量

Mysql Order By 字符串排序,mysql 字符串order by

MySQL 获取 ORDER BY 编号错误的行位置

Django order_by() 没有正确排序

java中如何实现mysql中的group by order by count()功能