2012-09-24 12 views
6

Ho un problema di ordinamento con oracle 10g. Non sono sicuro se è specifico per 10 g oppure no.Oracle 10g Ordinamento SQL VARCHAR2

Ho la seguente tabella:

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 

Esecuzione generico SELECT NAME FROM table_name ORDER BY 1 produce:

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 

desidero per ordinare correttamente quando detti profilati hanno numeri superiori 9, in questo modo:

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 

Ho molto più voci di numero di questo w con lunghezze diverse e molte sezioni con segmenti di numeri superiori a 10. Stavo cercando di scherzare con regexp_replace() nell'ordine in base alla clausola ma non ho avuto fortuna. Qualsiasi aiuto sarebbe molto apprezzato.

risposta

2

Prova questa

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 è un violino

+0

Questo funziona sicuramente. Puoi spiegare cosa sta succedendo? Inoltre questa è una grossa query che impiega molto tempo per generare. È a causa del With/Replace o della concatenazione in ORDER BY? Grazie. –

+0

Per prima cosa rende un xml (non proprio necessario, può essere fatto anche con substr e instr - in realtà ciò può costare in termini di prestazioni). poi prende ogni nodo (una parte tra i punti) e lo riempie di zero per essere di una lunghezza elevata (diciamo 5). ora può essere ordinato –

1

Quanto segue potrebbe darti un'idea di cosa fare. Per ordinare i valori del modulo "A", è possibile ordinare in base alla lunghezza dell'espressione seguita dall'espressione. Quindi, A.1 e A.2 sono prima di A.10, perché la loro lunghezza è più breve.

È possibile espandere questo, con un ordine come segue:

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

Non sono sicuro di seguire la logica del codice. C'è una parentesi mancante o sono il substr substr, len, substr all'interno della prima istruzione len? –

+0

Questa è una soluzione piuttosto buona ma gestisce solo una quantità limitata di punti. – Luke101

+0

@ Luke101. . . Lo scopo del "...." indica che il codice può essere esteso utilizzando la stessa struttura delle altre linee. –

0

Ecco un modo per farlo. Non sto dicendo che questo è l'unico o anche il modo migliore, ma è Un modo:

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

Condividere e godere.

+0

Questo account è dovuto al fatto che ho una lunghezza variabile di caratteri e sezioni DOT? –

0

Utilizzando espressioni regolari in grado di risolvere il problema,

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

Che questa domanda vuol dire che sto sostituendo i caratteri alfabetici + il ' .' carattere dalla colonna NOME, che copre il numero e quindi l'ordinamento.

Spero sia stato utile, buon divertimento!

+0

Non avrebbe risolto questa soluzione A.5.11 prima di A.5.10.1 – Luke101

+0

Questo tipo di funziona, ma li ordina in base alla lunghezza della stringa prima e quindi nell'ordine corretto. –

0

La mia domanda è stata effettivamente risposta in un altro post che ho postato per un problema simile ma non correlato.

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

Grazie a acheong87 per la soluzione. Oracle SQL Regexp_replace matching

Problemi correlati