为 varchar 类型的列排序

Order by for column in varchar type

我有以下列 strand,它按升序排列,但它在 3.1 而不是 3.2..

之后将 3.10 作为下一个

该列是 varchar 类型..

 Strand
 3.1
 3.1.1
 3.1.1.1
 3.1.1.2
 3.1.2
 3.1.2.1
 3.10       # wrong  
 3.10.1     # wrong
 3.10.1.1   # wrong
 3.2        <- this should have been after 3.1.2.1
 3.2.1
 3.2.1.1
 ..
 3.9
 3.9.1.1
         <- here is where 3.10 , 3.10.1 and 3.10.1.1 should reside

我使用以下查询来订购;

SELECT * FROM [table1]
ORDER BY RPAD(Strand,4,'.0') ;

如何确保它以正确的方式排序,以便 3.10、3.10.1 和 3.10.1.1 最后出现

您可以根据字段的整数值对结果进行排序。你的代码看起来像

select [myfield]from [mytable] order by 
convert(RPAD(replace([myfield],'.',''),4,0),UNSIGNED INTEGER);

在此代码中,替换函数将清除点 (.)
希望瘦身帮助

您必须规范化每组数字

SELECT * FROM [table1]
ORDER BY CONCAT(
    LPAD(SUBSTRING_INDEX(Strand,'.',1),3,'0'), '-',
    LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(Strand,'.',2),'.',-1),3,'0'), '-',
    LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(Strand,'.',3),'.',-1),3,'0'), '-',
    LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(Strand,'.',3),'.',-1),3,'0'));

样本

mysql> SELECT CONCAT(
    ->     LPAD(SUBSTRING_INDEX('3.10.1.1','.',1),3,'0'), '-',
    ->     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',2),'.',-1),3,'0'), '-',
    ->     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',3),'.',-1),3,'0'), '-',
    ->     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',3),'.',-1),3,'0'));
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CONCAT(
    LPAD(SUBSTRING_INDEX('3.10.1.1','.',1),3,'0'), '-',
    LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',2),'.',-1),3,'0'), '-',
    LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',3),'.',-1),3,'0'), '-',
    LPAD(SUBSTRING_INDEX(SUBSTRI |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 003-010-001-001                                                                                                                                                                                                                                                  |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)

如果你数据中的点(.)不超过3,你可以试试这个:

select *
from demo
order by replace(Strand, '.', '') * pow(10, (3 + length(replace(Strand, '.', '')) - length(Strand)))

如果点数不确定,这里可以使用子查询获取最大点数:

select demo.Strand
from demo
cross join (
    select max(length(Strand) - length(replace(Strand, '.', ''))) as num from demo
) t
order by replace(Strand, '.', '') * pow(10, (num + length(replace(Strand, '.', '')) - length(Strand)))

请参阅 Rextester 中的 demo

如您所见,我在 order by 子句中使用了函数 replace, length, pow

1) replace(Strand, '.', '') 会给我们整数,比如:
replace('3.10.1.1', '.', '') => 31011;
2) (3 + length(replace(Strand, '.', '')) - length(Strand)) 将给我们点的计数,即最大点数减去 Strand 中点的计数,如:
3.1 => 2;
3)powreturnsX的Y次方的值;

因此示例数据将计算如下:

3100
3110
3111
3112
3120
3121
31000
31010
31011
3200
3210
3211
3900
3911

根据这些数字,您将得到正确的排序。

原因"strand"列是文本数据,所以会按字母顺序排列。为了按照您的意愿进行排序,您应该在插入或更新数据之前格式化数据。假设每个级别的最大位数是 3,你的数据应该这样格式化

 003.001
 003.001.001
 003.001.001.001
 003.002
 003.002.001
 003.002.001.001
 003.010
 010.001

另一种方法是将 "strand" 列拆分为多个列。每一列都会存储每一级的数据,比如

Level1 | Level2 | Level3 ... 
3      | 1      | 0
3      | 1      | 1
3      | 2      | 0
...
3      | 10     | 0

这些列的数据类型应为数字,然后您应该可以按这些列进行排序。

试试这个:

DROP TABLE T1;
CREATE TABLE T1 (Strand VARCHAR(20));
INSERT INTO T1 VALUES ('3.1');
INSERT INTO T1 VALUES('3.1.1');
INSERT INTO T1 VALUES('3.1.1.1');
INSERT INTO T1 VALUES('3.1.1.2');
INSERT INTO T1 VALUES('3.2');
INSERT INTO T1 VALUES('3.2.1');
INSERT INTO T1 VALUES('3.10');
INSERT INTO T1 VALUES('3.10.1');

SELECT * FROM T1 
ORDER BY STRAND;


SELECT *
  FROM T1 
  ORDER BY 
    CAST(SUBSTRING_INDEX(CONCAT(Strand+'.0.0.0.0','.',1) AS UNSIGNED INTEGER) *1000 +
    CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Strand,'.0.0.0.0'),'.',2),'.',-1)  AS UNSIGNED INTEGER) *100 +
    CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Strand,'.0.0.0.0'),'.',3),'.',-1) AS UNSIGNED INTEGER) *10 +
    CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Strand,'.0.0.0.0'),'.',4),'.',-1)  AS UNSIGNED INTEGER)

输出未排序:

    Strand
1   3.1
2   3.1.1
3   3.1.1.1
4   3.1.1.2
5   3.10
6   3.10.1
7   3.2
8   3.2.1

输出顺序:

    Strand
1   3.1
2   3.1.1
3   3.1.1.1
4   3.1.1.2
5   3.2
6   3.2.1
7   3.10
8   3.10.1