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 に答える