2012-09-24 11 views
6

Oracle 10gでソートの問題が発生しています。 10gに特有のものかどうかは不明です。Oracle 10g SQLソートVARCHAR2

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が生成する実行::私はそれらのセクションがそうのように、9より大きい数字を持っている場合、正しくソートするためにそれをしたいと思い

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 

私は、次の表を持っている

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 

私にはこれより多くの番号の項目があります私は、order by節でregexp_replace()を使いこなそうとしていましたが、運がなかったのです。どんな助けでも大歓迎です。

答えて

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') 

Hereは、正規表現を使用したフィドル

+0

これは間違いなく機能します。何が起こっているのか説明できますか?また、それは生成に多くの時間を費やしている膨大なクエリです。これは、With/ReplaceまたはORDER BYの連結のためですか?ありがとうございました。 –

+0

まず、それをxmlにします(実際には必要ありません。substrとinstrを使って行うこともできます - 実際にはこれは実行に費用がかかるかもしれません)。すべてのノード(ドット間の部分)を取り、その長さがゼロになるようにパッドを貼り付けます(5とします)。今すぐソートすることができます –

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)) . . . 
+0

私はコードロジックに従っているかどうかはわかりません。最初のlen文の中に括弧がないか、それに続くsubstr、len、substrはありますか? –

+0

これはかなり良い解決策ですが、限られた量のドットしか扱えません。 – Luke101

+0

@ Luke101 。 。 「...」の目的は、他の行と同じ構造を使用してコードを拡張できることを示すことです。 –

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); 

を共有し、お楽しみください。

+0

私は文字とDOTセクションの長さが変わっているという事実を説明しますか? –

0

はあなたの問題を解決することができますで試してみてください、このクエリは、私は+アルファの文字を置き換える "だということを意味何

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

。 NAME列から文字を取り出し、番号をつけてソートします。

私はこれが役に立ちました、楽しいと思います!

+0

この解決策はA.5.10より前にソートA.5.10.1 – Luke101

+0

そのような仕組みですが、最初に文字列の長さに従って並べ替え、次に正しい順序でソートします。 –

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 matching