2015-04-17 60 views
12

Ho una tabella con un campo varchar. Questo campo memorizza i numeri gerarchici che voglio ordinare.Ordinamento del testo gerarchico in SQL

Ecco un esempio dei miei dati:

1 
1.1 
1.1.1 
1.1.2 
1.1.3. 
1.1.4 
1.1.5 
1.1.6. 
1.1.7 
10. 
10.1 
10.2 
10.3 
11. 
11.1 
11.2 
2. 
2.1 
1.2.2 
1.2.2.1 
1.2.2.2 

Come posso raggiungere il seguente risultato con T-SQL:

1 
1.1 
1.1.1 
1.1.2 
1.1.3 
1.1.4 
1.1.5 
1.1.6 
1.1.7 
1.2.2 
1.2.2.1 
1.2.2.2 
2. 
2.1 
10. 
10.1 
10.2 
10.3 
11. 
11.1 
11.2 

ho cercato di dividere le parti con il seguente SQL, ma questo è non elegante

SELECT CASE WHEN CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','')) = 0 
    THEN SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','') 
    ELSE REPLACE(SUBSTRING(SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.',''),1, CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.',''))),'.','') 
    END AS FIRST_PART 
,CASE WHEN CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','')) > 0 
     THEN SUBSTRING( 
SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','') 
    ,CHARINDEX('.',SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','')) +1 
    ,LEN(SUBSTRING(LTRIM(RTRIM(NR)),1,LEN(NR)-1)+REPLACE(SUBSTRING(LTRIM(RTRIM(NR)),LEN(NR),1),'.','') ) 
    ) 
    ELSE '0' 
    END AS SECOND_PART 
FROM TEST_TABLE 

C'è un modo migliore per farlo?

+0

Rapporti negozio invece di. articoli separati come valori di colonna? – jarlh

+0

Posso solo eseguire un SELECT e non ho la possibilità di memorizzare le relazioni – h0mebrewer

+2

http://stackoverflow.com/questions/6446000/properly-sorting-dumper-numbers-stored-as-character-in-sql-server – niyou

risposta

6

Prova questo:

DECLARE @DataSource TABLE 
(
    [Value] VARCHAR(12) 
); 

INSERT INTO @DataSource ([Value]) 
VALUES ('1') 
     ,('1.1') 
     ,('1.1.1') 
     ,('1.1.2') 
     ,('1.1.3.') 
     ,('1.1.4') 
     ,('1.1.5') 
     ,('1.1.6.') 
     ,('1.1.7') 
     ,('10.') 
     ,('10.1') 
     ,('10.2') 
     ,('10.3') 
     ,('11.') 
     ,('11.1') 
     ,('11.2') 
     ,('2.') 
     ,('2.1') 
     ,('1.2.2') 
     ,('1.2.2.1') 
     ,('1.2.2.2'); 

SELECT * 
FROM @DataSource 
ORDER BY CAST('/' + IIF(RIGHT([Value],1) = '.', LEFT([Value], LEN([Value]) - 1), [Value]) + '/' AS HIERARCHYID); 

È possibile controllare il hierarchyid per maggiori dettagli. Il controllo nella clausola ORDER BY rimuove solo lo . alla fine del valore (se tale esiste).


È possibile modificare la funzione IIF con semplici CASE WHEN come questo:

SELECT * 
FROM @DataSource 
ORDER BY CAST('/' + CASE WHEN RIGHT([Value],1) = '.' THEN LEFT([Value], LEN([Value]) - 1) ELSE [Value] END + '/' AS HIERARCHYID); 
+0

Funziona solo con SQL Server 2012 e versioni successive. IIF non è disponibile su SQL Server 2008 – h0mebrewer

+0

@ h0mebrewer È possibile modificare facilmente 'IIF' con' CASE WHEN' - controllare la modifica. – gotqn

-1

rimuovere punti e ordine:

select column from table order by replace(column,'.','') 

e non c'è necessità di convertire varchar al numero se si vuoi 10 a venire prima 2.

+0

Non voglio 10 per 2. – h0mebrewer