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

pepwfjgg  于 2021-06-18  发布在  Mysql
关注(0)|答案(4)|浏览(335)

我没有这样的价值观

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\u no值属于同一表的同一字段和不同行。
我不知道从现在开始该怎么办。
任何帮助都将不胜感激。
编辑
下面是一个示例数据库。

bttbmeg0

bttbmeg01#

最好的方案是创建两个额外的列,一个用于字母部分,一个用于数字部分;那就简单到 ORDER BY alpha_part ASC, num_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;
jk9hmnmh

jk9hmnmh2#

由于mysql版本<8.0中缺少regex函数,我们可以创建一个自定义函数从给定字符串中提取数字子字符串。
下面是这个答案的修改后的函数,它从输入字符串返回整数值。这里所做的修改是它返回string而不是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 ;

现在,您可以使用这个自定义函数,按字母部分排序,然后按数字部分排序(转换为 unsigned ).

SELECT id, 
       name,
       REPLACE(name, ExtractNumber(name), '') as strpart, 
       CAST(ExtractNumber(name) AS UNSIGNED) as numpart 
FROM test
ORDER BY strpart, 
         numpart

db小提琴演示

sqougxex

sqougxex3#

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

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

rta7y2nd4#

不漂亮,正如前面所说,因为我们是字符串解析,它将是缓慢的。这假设您的格式是字母,然后数字值从不混合。它找到第一个数值,然后根据这个结果分成两列。
演示:
我只想按qt\u no+0排序以获得自然排序,但这不起作用。所以我走了另一条路。。。。
field1是你的qt\u 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

相关问题