6

我在使用 oracle 10g 时遇到排序问题。不确定它是否特定于 10g。

我有下表:

ID  NAME
 1  A.1
 2  A.3
 3  A.4
 4  A.5
 5  A.2
 6  A.5.1
 7  A.5.2
 8  A.5.10
 9  A.5.10.1
10  A.5.3

执行泛型SELECT NAME FROM table_name ORDER BY 1会产生:

A.1
A.2
A.3
A.4
A.5
A.5.1
A.5.10
A.5.10.1
A.5.2
A.5.3

当这些部分的数字大于 9 时,我希望它能够正确排序,如下所示:

A.1
A.2
A.3
A.4
A.5
A.5.1
A.5.2
A.5.3
A.5.10
A.5.10.1

我有比这更多的数字条目,长度不同,许多部分的数字段大于 10。我试图在 order by 子句中弄乱 regexp_replace() 但没有运气。任何帮助将不胜感激。

4

5 回答 5

2

试试这个

WITH t AS
(
  SELECT id,name,
  xmltype('<r><c>' ||replace(NAME, '.', '</c><c>')||'</c></r>') AS xmlname
  FROM table1
)

SELECT name ,id
FROM t
ORDER BY lpad(extract(xmlname,'//c[1]/text()').getstringval(), 5, '0')
||lpad(extract(xmlname,'//c[2]/text()').getstringval(), 5, '0')
||lpad(extract(xmlname,'//c[3]/text()').getstringval(), 5, '0')
||lpad(extract(xmlname,'//c[4]/text()').getstringval(), 5, '0')

是一个小提琴

于 2012-09-25T00:26:16.813 回答
1

以下内容可能会让您知道该怎么做。要对“A.”形式的值进行排序,您可以按表达式的长度后跟表达式进行排序。所以,A.1 和 A.2 在 A.10 之前,因为它们的长度更短。

您可以按以下顺序扩展它:

order by substr(val, 1, instr('.')),
         len(substr(val, 1, instr('.', 1, 2)),
         substr(val, 1, instr('.', 1, 2)),
         len(substr(val, 1, instr('.', 1, 3)),
         substr(val, 1, instr('.', 1, 3)) . . .
于 2012-09-24T17:55:39.507 回答
0

这是一种方法。我并不是说这是唯一甚至最好的方法,但它是一种方法:

SELECT ID,
       NAME
FROM
  (SELECT ID, NAME,
       INSTR(NAME, '.', 1, 1) AS FIRST_DOT_INDEX,
       INSTR(NAME, '.', 1, 2) AS SECOND_DOT_INDEX,
       INSTR(NAME, '.', 1, 3) AS THIRD_DOT_INDEX,
       INSTR(NAME, '.', 1, 4) AS FOURTH_DOT_INDEX
     FROM test_table)
ORDER BY SUBSTR(NAME, 1, FIRST_DOT_INDEX-1),
         TO_NUMBER(SUBSTR(NAME, FIRST_DOT_INDEX+1, (CASE WHEN SECOND_DOT_INDEX>0
                                                      THEN SECOND_DOT_INDEX-1
                                                      ELSE LENGTH(NAME)
                                                    END - FIRST_DOT_INDEX))),
         TO_NUMBER(CASE WHEN SECOND_DOT_INDEX = 0 AND THIRD_DOT_INDEX = 0
                     THEN '0'
                     ELSE SUBSTR(NAME, SECOND_DOT_INDEX+1, (CASE WHEN THIRD_DOT_INDEX>0
                                                              THEN THIRD_DOT_INDEX-1
                                                              ELSE LENGTH(NAME)
                                                            END - SECOND_DOT_INDEX)) 
                   END),
         TO_NUMBER(CASE WHEN THIRD_DOT_INDEX > 0
                     THEN SUBSTR(NAME, THIRD_DOT_INDEX+1, LENGTH(NAME) - THIRD_DOT_INDEX)
                     ELSE '0'
                   END);

分享和享受。

于 2012-09-24T19:09:53.403 回答
0

使用正则表达式可以解决您的问题,

select *
from new_table
  order by to_number(regexp_replace(name,'[[:alpha:].]*'));

这个查询意味着我正在替换字母字符 + '。' NAME 列中的字符,转换为数字然后排序。

我希望这是有帮助的,享受!

于 2012-09-25T15:50:32.180 回答
0

我的问题实际上在我针对类似但不相关的问题发布的另一篇文章中得到了回答。

Oracle SQL doesn't support lookaround assertions, which would be useful for this case:

s/([0-9](?<![0-9]))/0\1/g

You'll have to use at least two replacements:

REGEXP_REPLACE(REGEXP_REPLACE(col, '([0-9]+)', '0\1'), '0([0-9]{2})', '\1')`

感谢 acheong87 的解决方案。 Oracle SQL Regexp_replace 匹配

于 2012-09-25T17:00:29.537 回答