在 mysql 和 oracle db 中将字符串排序为数字

Sorting strings as number in mysql and oracle db

我有两个数据库列(数据类型为 varchar),其中包含如下值

column 1 
--------
1.8.0
1.7.0
9.0
10.0

column 2
--------
121
65
78

在 UI 我必须合并这两列并显示像

这样的值
1.8.0_121
1.8.0_78

问题出在对 UI 上显示的组合列进行排序时。由于两列都是 db 中的 varchar order by 正在使用字符串发生,并且 121 在 78 之前出现,这对于升序是错误的。

作为解决方案,我在这些列上将 ABS 用于 mysql,将 to_number 用于 oracle。 MySQL 对两列都工作正常,但 Oracle to_number 对第一列抛出错误 "Invalid number",因为它的值为 1.8.0

请建议如何仅使用代码更改来处理这种情况。由于进行数据库架构更改会导致许多系统发生大量更改,因此不想触及它。

样本 table 数据

使用 order by 子句查询

SELECT (MAJOR || '_' || MINOR) AS VER 
FROM VERSION 
ORDER BY MAJOR ASC, MINOR ASC

结果

更正了将 varchar 列视为数字的查询

SELECT (MAJOR || '_' || MINOR) AS VER 
FROM VERSION 
ORDER BY MAJOR ASC, TO_NUMBER(MINOR) ASC

更正结果

到目前为止一切都很好。但问题是 MAJOR 列可以有像 9.0 和 10.0 这样的值,所以我想按子句的顺序也转换主要列 to_number 以便排序是正确的。但由于值为 1.8.0,因此会出现抛出错误。

有问题的案例是

一个选项是提取所有数字部分(使用正则表达式;我认为这是最简单的选项),对它们应用 TO_NUMBER 并按这些值排序,例如

SQL> with test (col) as
  2    (select '1.8.0' from dual union
  3     select '1.7.0' from dual union
  4     select '9.0'   from dual union
  5     select '10.0'  from dual
  6    )
  7  select col
  8  from test
  9  order by to_number(regexp_substr(col, '\d+', 1, 1)),
 10           to_number(regexp_substr(col, '\d+', 1, 2)),
 11           to_number(regexp_substr(col, '\d+', 1, 3));

COL
-----
1.7.0
1.8.0
9.0
10.0

SQL>

这是一个技巧...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(column1 VARCHAR(12) NOT NULL
,column2 DECIMAL(5,2) NULL
);


INSERT INTO my_table VALUES
('1.8.0',121),
('1.7.0',65),
('9.0',78),
('10.0',NULL);

SELECT a.column1
     , b.column2 
  FROM 
     (SELECT column1,@i:=@i+1 i FROM my_table,(SELECT @i:=0) vars ORDER BY INET_ATON(column1))a
  JOIN
     (SELECT column2,@j:=@j+1 j FROM my_table,(SELECT @j:=0) vars ORDER BY ISNULL(column2),column2)b
    ON b.j = a.i;
+---------+---------+
| column1 | column2 |
+---------+---------+
| 1.7.0   |   65.00 |
| 1.8.0   |   78.00 |
| 9.0     |  121.00 |
| 10.0    |    NULL |
+---------+---------+

这个查询适合我。

SELECT ( major 
     || '_' 
     || minor ) AS ver 
FROM   
(SELECT major, minor, 
    To_number(Replace(Decode(Substr(major, 0, 2), '1.',Substr(major, 3), major), '.', '')) 
      AS major_num, 
    To_number(Decode(Instr(minor, '-'), 0, minor,Substr(minor, 0, Instr(minor, '-') - 1))) 
      AS minor_num 
FROM   version) 
ORDER  BY major_num, 
      minor_num;