在 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;
我有两个数据库列(数据类型为 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;