2012-09-24 21 views
6

Mam problem z sortowaniem z Oracle 10g. Nie jestem pewien, czy to jest specyficzne dla 10g czy nie.Oracle Sortowanie SQL 10g VARCHAR2

mam poniższej tabeli:

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 

wykonaniem generic SELECT NAME FROM table_name ORDER BY 1 produkuje:

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 

chciałbym go rozwiązać poprawnie, gdy te odcinki mają numery większe niż 9, tak jak poniżej:

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 

Mam znacznie więcej wpisów liczbowych niż to - o różnych długościach i wielu sekcjach o numerach większych niż 10. Próbowałem zadziwić się z regexp_replace() w kolejności klauzuli, ale nie miałem szczęścia. Każda pomoc będzie wielce ceniona.

Odpowiedz

2

Spróbuj

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 jest skrzypce

+0

To zdecydowanie działa. Czy możesz wyjaśnić, co się dzieje? Również to jest mocne zapytanie, które zabiera dużo czasu na wygenerowanie. Czy to z powodu opcji Z/Zamień, czy konkatenacji w ZAMÓWIENIU? Dziękuję Ci. –

+0

Po pierwsze powoduje, że jest to xml (niezbyt potrzebny, można to zrobić również z substr i instr - w rzeczywistości może to kosztować wydajność). następnie bierze każdy węzeł (część między kropkami) i nakłada na niego zera na dużą długość (powiedzmy 5). teraz można go sortować –

1

Poniższe mogą dać ci pojęcie, co robić. Aby zamówić wartości w formularzu "A.", można zamówić przez długość wyrażenia, po którym następuje wyrażenie. A.1 i A.2 mają przed A.10, ponieważ ich długość jest krótsza.

Możesz rozwinąć ten, z zamówieniem przez następująco:

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

Nie jestem pewien, czy stosuję się do logiki kodu. Czy brakuje nawiasu lub czy kolejny substr, len, substr w pierwszym poleceniu len? –

+0

To całkiem dobre rozwiązanie, ale obsługuje tylko ograniczoną liczbę kropek. – Luke101

+0

@ Luke101. . . Cel ". ..." oznacza, że ​​kod można rozszerzyć przy użyciu tej samej struktury, co pozostałe linie. –

0

Oto sposób, aby to zrobić. Nie mówię, że jest to jedyny ani nawet najlepszy sposób, ale jest sposób:

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

Podziel się i cieszyć.

+0

Czy to oznacza, że ​​mam różne długości znaków i sekcje DOT? –

0

Korzystanie regex można rozwiązać problemu,

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

Co oznacza ta kwerenda, że ​​jestem zastępując znaki alfa + Klasa " . " znak z kolumny NAZWA, zakrywanie na numer, a następnie sortowanie.

Mam nadzieję, że to było pomocne, baw się dobrze!

+0

Nie należy tego sortować A.5.11 przed A.5.10.1 – Luke101

+0

Ten rodzaj utworów, ale sortuje je według długości ciągu, a następnie we właściwej kolejności. –

0

Moje pytanie zostało udzielone w innym poście opublikowanym dla podobnego, ale niezwiązanego problemu.

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

Dzięki acheong87 za rozwiązanie. Oracle SQL Regexp_replace matching

Powiązane problemy