Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何对包含数字和字母的字符串进行排序?_Mysql_Sorting_Mysql 5.7 - Fatal编程技术网

Mysql 如何对包含数字和字母的字符串进行排序?

Mysql 如何对包含数字和字母的字符串进行排序?,mysql,sorting,mysql-5.7,Mysql,Sorting,Mysql 5.7,我没有值,例如 AM1,M3,M4,M14,M30,M40,MA01,A10,A13,A07,B01,B10,Z33,Z13 etc(实际上是字母后的任何整数2-3位数) 我试着把它分类为 order by length(qt_no), qt_no 它没有达到我要求的输出 我的预期产出是 A01,A07,A10,A13,B01,AM1,M3,M4,M14,M30,M40,MA01,Z13,Z33 请记住,这些qt_no值属于同一表的同一字段和不同行 我不知道从现在起该怎么办 任何帮助都将不

我没有值,例如

AM1,M3,M4,M14,M30,M40,MA01,A10,A13,A07,B01,B10,Z33,Z13
etc(实际上是字母后的任何整数2-3位数)

我试着把它分类为

order by length(qt_no), qt_no
它没有达到我要求的输出

我的预期产出是

A01,A07,A10,A13,B01,AM1,M3,M4,M14,M30,M40,MA01,Z13,Z33
请记住,这些qt_no值属于同一表的同一字段和不同行

我不知道从现在起该怎么办

任何帮助都将不胜感激

编辑


下面是一个示例数据库。

最好的方案是创建两个额外的列,一个用于字母部分,一个用于数字部分;然后它就简单到按alpha\u part ASC、num\u part ASC进行排序。如果在这两列上有一个联合索引,它也会非常快

如果您必须在查询时解析该列,那么这需要时间,而且索引也会变得无用,这会使一切变得非常缓慢。但你可以这样做:

...
ORDER BY
  REGEXP_REPLACE(qt_no, '\d+', '') ASC, 
  CAST(REGEXP_REPLACE(qt_no, '\D+', '') AS INTEGER) ASC
编辑:我很抱歉,但我不知道如何在5.7上完成,除了这样:

SELECT qt_no FROM t
ORDER BY
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(qt_no, '0', ''), '1', ''), '2', ''), '3', ''), '4', ''), '5', ''), '6', ''), '7', ''), '8', ''), '9', '') ASC, 
CAST(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(qt_no, 'A', ''), 'B', ''), 'C', ''), 'D', ''), 'E', ''), 'F', ''), 'G', ''), 'H', ''), 'I', ''), 'J', ''), 'K', ''), 'L', ''), 'M', ''), 'N', ''), 'O', ''), 'P', ''), 'Q', ''), 'R', ''), 'S', ''), 'T', ''), 'U', ''), 'V', ''), 'W', ''), 'X', ''), 'Y', ''), 'Z', '') AS UNSIGNED) ASC;

最好的方案是创建两个额外的列,一个用于字母部分,一个用于数字部分;然后它就简单到按alpha\u part ASC、num\u part ASC进行排序。如果在这两列上有一个联合索引,它也会非常快

如果您必须在查询时解析该列,那么这需要时间,而且索引也会变得无用,这会使一切变得非常缓慢。但你可以这样做:

...
ORDER BY
  REGEXP_REPLACE(qt_no, '\d+', '') ASC, 
  CAST(REGEXP_REPLACE(qt_no, '\D+', '') AS INTEGER) ASC
编辑:我很抱歉,但我不知道如何在5.7上完成,除了这样:

SELECT qt_no FROM t
ORDER BY
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(qt_no, '0', ''), '1', ''), '2', ''), '3', ''), '4', ''), '5', ''), '6', ''), '7', ''), '8', ''), '9', '') ASC, 
CAST(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(qt_no, 'A', ''), 'B', ''), 'C', ''), 'D', ''), 'E', ''), 'F', ''), 'G', ''), 'H', ''), 'I', ''), 'J', ''), 'K', ''), 'L', ''), 'M', ''), 'N', ''), 'O', ''), 'P', ''), 'Q', ''), 'R', ''), 'S', ''), 'T', ''), 'U', ''), 'V', ''), 'W', ''), 'X', ''), 'Y', ''), 'Z', '') AS UNSIGNED) ASC;

您可以将顺序分为三个阶段:首先是字母,然后是字符串的长度,最后是字母顺序:

select * from test order by substring( qt_no, 1, 1 ), length(qt_no), qt_no;

您可以将顺序分为三个阶段:首先是字母,然后是字符串的长度,最后是字母顺序:

select * from test order by substring( qt_no, 1, 1 ), length(qt_no), qt_no;

不漂亮,正如我们已经说过的,因为我们正在进行字符串解析,它会很慢。 这假设您的格式是字母,然后数字值从不混合。它查找第一个数值,然后根据该查找结果拆分为两列

我只是想按qt_no+0进行排序,以获得自然排序,但这不起作用。 所以我走了另一条路

Field1是您的qt_no字段

SELECT Field1,

#Use this to just get the number values but since we lose trailing zeros...Step 2 we reverse the value so numbers are first allowing the convert to drop the letters.  unfortunately this also drops the trailing (leading since we reversed) zeros.
       @NumStep1 := reverse(CONVERT(reverse(Field1), SIGNED)) NumStep1,

#We got the postiion of the first number... so get the  whole number now.
       @NumStep2 :=substring(Field1,locate(@numStep1,Field1),length(Field1)) NumStep2,
       @Alpha:= substring(Field1,1,Locate(@numStep2,Field1)-1) Alpha

FROM (
SELECT 'AM1' as Field1 UNION ALL 
SELECT 'M3' as Field1 UNION ALL
SELECT 'M4' as Field1 UNION ALL
SELECT 'M14' as Field1 UNION ALL
SELECT 'M30' as Field1 UNION ALL
SELECT 'M40' as Field1 UNION ALL
SELECT 'MA01' as Field1 UNION ALL
SELECT 'A10' as Field1 UNION ALL
SELECT 'A13' as Field1 UNION ALL
SELECT 'A07' as Field1 UNION ALL
SELECT 'B01' as Field1 UNION ALL
SELECT 'B10' as Field1 UNION ALL
SELECT 'Z33' as Field1 UNION ALL
SELECT 'Z13' as Field1) Z
ORDER BY Alpha, NumStep2*1
给了我们:

+----+--------+----------+----------+-------+
|    | Field1 | NumStep1 | NumStep2 | Alpha |
+----+--------+----------+----------+-------+
|  1 | A10    |        1 |       10 | A     |
|  2 | A13    |       13 |       13 | A     |
|  3 | A07    |       07 |       07 | A     |
|  4 | AM1    |        1 |        1 | AM    |
|  5 | B10    |        1 |       10 | B     |
|  6 | B01    |       01 |       01 | B     |
|  7 | M3     |        3 |        3 | M     |
|  8 | M4     |        4 |        4 | M     |
|  9 | M14    |       14 |       14 | M     |
| 10 | M30    |        3 |       30 | M     |
| 11 | M40    |        4 |       40 | M     |
| 12 | MA01   |       01 |       01 | MA    |
| 13 | Z33    |       33 |       33 | Z     |
| 14 | Z13    |       13 |       13 | Z     |
+----+--------+----------+----------+-------+
没有用户变量,但将数据拆分为字母和数字

SELECT Field1,
       substring(Field1,locate(reverse(CONVERT(reverse(Field1), SIGNED)),Field1),length(Field1)) NumStep2,
       substring(Field1,1,Locate(substring(Field1,locate(reverse(CONVERT(reverse(Field1), SIGNED)),Field1),length(Field1)),Field1)-1) Alpha

FROM (
SELECT 'AM1' as Field1 UNION ALL 
SELECT 'M3' as Field1 UNION ALL
SELECT 'M4' as Field1 UNION ALL
SELECT 'M14' as Field1 UNION ALL
SELECT 'M30' as Field1 UNION ALL
SELECT 'M40' as Field1 UNION ALL
SELECT 'MA01' as Field1 UNION ALL
SELECT 'A10' as Field1 UNION ALL
SELECT 'A13' as Field1 UNION ALL
SELECT 'A07' as Field1 UNION ALL
SELECT 'B01' as Field1 UNION ALL
SELECT 'B10' as Field1 UNION ALL
SELECT 'Z33' as Field1 UNION ALL
SELECT 'Z13' as Field1) Z
ORDER BY Alpha, NumStep2*1

不漂亮,正如我们已经说过的,因为我们正在进行字符串解析,它会很慢。 这假设您的格式是字母,然后数字值从不混合。它查找第一个数值,然后根据该查找结果拆分为两列

我只是想按qt_no+0进行排序,以获得自然排序,但这不起作用。 所以我走了另一条路

Field1是您的qt_no字段

SELECT Field1,

#Use this to just get the number values but since we lose trailing zeros...Step 2 we reverse the value so numbers are first allowing the convert to drop the letters.  unfortunately this also drops the trailing (leading since we reversed) zeros.
       @NumStep1 := reverse(CONVERT(reverse(Field1), SIGNED)) NumStep1,

#We got the postiion of the first number... so get the  whole number now.
       @NumStep2 :=substring(Field1,locate(@numStep1,Field1),length(Field1)) NumStep2,
       @Alpha:= substring(Field1,1,Locate(@numStep2,Field1)-1) Alpha

FROM (
SELECT 'AM1' as Field1 UNION ALL 
SELECT 'M3' as Field1 UNION ALL
SELECT 'M4' as Field1 UNION ALL
SELECT 'M14' as Field1 UNION ALL
SELECT 'M30' as Field1 UNION ALL
SELECT 'M40' as Field1 UNION ALL
SELECT 'MA01' as Field1 UNION ALL
SELECT 'A10' as Field1 UNION ALL
SELECT 'A13' as Field1 UNION ALL
SELECT 'A07' as Field1 UNION ALL
SELECT 'B01' as Field1 UNION ALL
SELECT 'B10' as Field1 UNION ALL
SELECT 'Z33' as Field1 UNION ALL
SELECT 'Z13' as Field1) Z
ORDER BY Alpha, NumStep2*1
给了我们:

+----+--------+----------+----------+-------+
|    | Field1 | NumStep1 | NumStep2 | Alpha |
+----+--------+----------+----------+-------+
|  1 | A10    |        1 |       10 | A     |
|  2 | A13    |       13 |       13 | A     |
|  3 | A07    |       07 |       07 | A     |
|  4 | AM1    |        1 |        1 | AM    |
|  5 | B10    |        1 |       10 | B     |
|  6 | B01    |       01 |       01 | B     |
|  7 | M3     |        3 |        3 | M     |
|  8 | M4     |        4 |        4 | M     |
|  9 | M14    |       14 |       14 | M     |
| 10 | M30    |        3 |       30 | M     |
| 11 | M40    |        4 |       40 | M     |
| 12 | MA01   |       01 |       01 | MA    |
| 13 | Z33    |       33 |       33 | Z     |
| 14 | Z13    |       13 |       13 | Z     |
+----+--------+----------+----------+-------+
没有用户变量,但将数据拆分为字母和数字

SELECT Field1,
       substring(Field1,locate(reverse(CONVERT(reverse(Field1), SIGNED)),Field1),length(Field1)) NumStep2,
       substring(Field1,1,Locate(substring(Field1,locate(reverse(CONVERT(reverse(Field1), SIGNED)),Field1),length(Field1)),Field1)-1) Alpha

FROM (
SELECT 'AM1' as Field1 UNION ALL 
SELECT 'M3' as Field1 UNION ALL
SELECT 'M4' as Field1 UNION ALL
SELECT 'M14' as Field1 UNION ALL
SELECT 'M30' as Field1 UNION ALL
SELECT 'M40' as Field1 UNION ALL
SELECT 'MA01' as Field1 UNION ALL
SELECT 'A10' as Field1 UNION ALL
SELECT 'A13' as Field1 UNION ALL
SELECT 'A07' as Field1 UNION ALL
SELECT 'B01' as Field1 UNION ALL
SELECT 'B10' as Field1 UNION ALL
SELECT 'Z33' as Field1 UNION ALL
SELECT 'Z13' as Field1) Z
ORDER BY Alpha, NumStep2*1

由于MySQL版本<8.0中缺少Regex函数,我们可以创建一个自定义函数,从给定字符串中提取数字子字符串

下面是由此修改的函数,它从输入字符串返回整数值。这里所做的修改是它返回字符串而不是Int。因为您有像
07
这样的数字字符串,需要按原样返回,而不是
7

DELIMITER $$

CREATE FUNCTION `ExtractNumber`(in_string VARCHAR(50)) 
RETURNS VARCHAR(50)
NO SQL
BEGIN
    DECLARE ctrNumber VARCHAR(50);
    DECLARE finNumber VARCHAR(50) DEFAULT '';
    DECLARE sChar VARCHAR(1);
    DECLARE inti INTEGER DEFAULT 1;

    IF LENGTH(in_string) > 0 THEN
        WHILE(inti <= LENGTH(in_string)) DO
            SET sChar = SUBSTRING(in_string, inti, 1);
            SET ctrNumber = FIND_IN_SET(sChar, '0,1,2,3,4,5,6,7,8,9'); 
            IF ctrNumber > 0 THEN
                SET finNumber = CONCAT(finNumber, sChar);
            END IF;
            SET inti = inti + 1;
        END WHILE;
        RETURN finNumber;
    ELSE
        RETURN '';
    END IF;    
END$$

DELIMITER ;

由于MySQL版本<8.0中缺少Regex函数,我们可以创建一个自定义函数,从给定字符串中提取数字子字符串

下面是由此修改的函数,它从输入字符串返回整数值。这里所做的修改是它返回字符串而不是Int。因为您有像
07
这样的数字字符串,需要按原样返回,而不是
7

DELIMITER $$

CREATE FUNCTION `ExtractNumber`(in_string VARCHAR(50)) 
RETURNS VARCHAR(50)
NO SQL
BEGIN
    DECLARE ctrNumber VARCHAR(50);
    DECLARE finNumber VARCHAR(50) DEFAULT '';
    DECLARE sChar VARCHAR(1);
    DECLARE inti INTEGER DEFAULT 1;

    IF LENGTH(in_string) > 0 THEN
        WHILE(inti <= LENGTH(in_string)) DO
            SET sChar = SUBSTRING(in_string, inti, 1);
            SET ctrNumber = FIND_IN_SET(sChar, '0,1,2,3,4,5,6,7,8,9'); 
            IF ctrNumber > 0 THEN
                SET finNumber = CONCAT(finNumber, sChar);
            END IF;
            SET inti = inti + 1;
        END WHILE;
        RETURN finNumber;
    ELSE
        RETURN '';
    END IF;    
END$$

DELIMITER ;


这是我的错误
REGEXP\u REPLACE不存在
可能是旧数据库<代码>REGEXP_REPLACE在8.0中提供。。。能否指定正在运行的版本?编辑:我刚刚在另一条评论中看到,5.7是的。我的服务器的mysql版本是5.7,你能不能至少给我一个查询,只获取字母和数字作为两个不同的字段,我会对这两个字段进行排序。因为数据库不能创建两个单独的字段。我希望你能理解我会实现你的编辑部分。但它仍然不起作用,我只是在你的小提琴上运行它,没有错误:它向我显示了错误
REGEXP\u REPLACE不存在
可能是旧数据库<代码>REGEXP_REPLACE在8.0中提供。。。能否指定正在运行的版本?编辑:我刚刚在另一条评论中看到,5.7是的。我的服务器的mysql版本是5.7,你能不能至少给我一个查询,只获取字母和数字作为两个不同的字段,我会对这两个字段进行排序。因为数据库不能创建两个单独的字段。我希望你能理解我会实现你的编辑部分。但是它仍然不起作用,我只是在你的小提琴中运行它,没有错误:gt_no column有什么类型?varchar(10),但我研究了一些,意识到,我需要自然排序顺序请创建一个SQL小提琴或DB小提琴,并将其添加到问题中,供其他人使用。你可以使用这个答案中创建的函数:从字符串中提取数字,从字符串中提取非数字部分。检查这个提琴:它对你有用吗?gt_no column有什么类型?varchar(10),但我研究了一些,意识到,我需要自然排序顺序请创建一个SQL FIDLE或DB FIDLE并将其添加到问题中,供其他人使用。您可以使用此答案中创建的函数:从字符串中提取数字,从字符串中提取非数字部分。检查此FIDLE:它对您有效吗?抱歉,伙计。但不确定字母或字母的数量可能以字符串形式出现。我需要自然排序顺序然后@Amadan answer是正确的,你只需要用正则表达式按字母顺序排序,然后按整数排序,现在在mysql中搜索正则表达式函数。。heheIt在服务器的mysql版本5.7中不可用。但具体数字还不确定