2009-05-20 12 views
5

Abbiamo un tavolo che ha la forma:singolo SQL SELECT multiple righe di una tabella fila

ID,Value1,Value2,Value3 
1,2,3,4 

dobbiamo trasformare questo in.

ID,Name,Value 
1,'Value1',2 
1,'Value2',3 
1,'Value3',4 

C'è un modo intelligente per farlo in una istruzione SELECT (cioè senza UNION)? I nomi di colonna Valore1, Valore2 e Valore3 sono fissi e costanti.

Il database è Oracle 9i.

+0

Che server DB stai usando? –

+0

Sono 1,2,3,4 colonne o valori di dati? –

+1

Il modo più intelligente che riesco a pensare è ridisegnare il database in modo che sia normalizzato :) –

risposta

3

Questo funziona su Oracle 10g:

select id, 'Value' || n as name, 
     case n when 1 then value1 when 2 then value2 when 3 then value3 end as value 
from (select rownum n 
     from (select 1 from dual connect by level <= 3)) ofs, t 

penso Oracle 9i aveva query ricorsive? Ad ogni modo, sono abbastanza sicuro che abbia il supporto di CASE, quindi anche se non ha query ricorsive, puoi semplicemente fare "(seleziona 1 da unione doppia seleziona 2 da unione doppia seleziona 3 da doppio)" invece. Abusare delle query ricorsive è un po 'più generale, per Oracle. (Utilizzare i sindacati per generare righe è comunque portatile per altri DB)

+0

+1 per la scansione di una singola tabella. Domande ricorsive WRT: Oracle ha avuto query gerarchiche dal 7, ma ha introdotto solo la clausola ricorsiva WITH in 11gR2. –

9

Dare un union un colpo.

select ID, 'Value1' as Name, Value1 as Value from table_name union all 
select ID, 'Value2', Value2 as Value from table_name union all 
select ID, 'Value3', Value3 as Value from table_name 

order by ID, Name 

utilizzando union all significa che il server non eseguirà una distinct (che è implicito in union operazioni). Non dovrebbe fare alcuna differenza con i dati (dato che il tuo ID dovrebbe essere HOPEFULLY diverso), ma potrebbe accelerarlo un po '.

+0

Bello, è così che lo farei: mi piace l'ottimizzazione UNION ALL. Errore minore: nell'esempio non c'è valore4. Immagino che un modo alternativo sia quello di unpivot, a seconda che il DB supporti questa funzionalità. – RichardOD

+0

L'utilizzo di 'union all' non influirà in alcun modo sull'output poiché 'Value1', 'Value2' e 'Value3' sono tutti distinti! Ma eviterà inutilmente che il DB provi a unificare le file. – araqnid

+0

Buona risposta, ma la domanda ha chiesto un modo * senza * sindacati! –

2

Si può fare in questo modo, ma non è abbastanza:

SELECT id,'Value 1' AS name,value1 AS value FROM mytable 
UNION 
SELECT id,'Value 2' AS name,value2 AS value FROM mytable 
UNION 
SELECT id,'Value 3' AS name,value3 AS value FROM mytable 
2

Unioning tre select dovrebbe fare il trucco:

SELECT ID, 'Value1', Value1 AS Value 
FROM TABLE 
UNION 
SELECT ID, 'Value2', Value2 AS Value 
FROM TABLE 
UNION 
SELECT ID, 'Value3', Value3 AS Value 
FROM TABLE 
0

Se stai usando SQL Server 2005 + allora si può usare UNPIVOT

CREATE TABLE #tmp (ID int, Value1 int, Value2 int, Value3 int) 

INSERT INTO #tmp (ID, Value1, Value2, Value3) VALUES (1, 2, 3, 4) 

SELECT 
    * 
FROM 
    #tmp 

SELECT 
    * 
FROM 
    #tmp 
UNPIVOT 
(
    [Value] FOR [Name] IN (Value1, Value2, Value3) 
) uPIVOT 

DROP TABLE #tmp 
-1

per SQL Server, considerare UNPIVOT come alternativa alla UNION:

SELECT id, value, colname 
FROM #temp t 
UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X 

Ciò restituirà anche il nome della colonna. Non sono sicuro di cosa sia la X, ma non puoi lasciarlo fuori.

0

UN UNIONE TUTTO, come altri hanno suggerito, è probabilmente la soluzione migliore in SQL. Si potrebbe anche voler considerare la gestione di questo nel front end a seconda di quali sono i requisiti specifici.

-1

Prova questo:

CTE crea una tabella temporanea con 4 valori. È possibile eseguire questo come è in qualsiasi database.

with TEST_CTE (ID) as 

(select * from (select '1' as a) as aa union all 
select * from (select '2' as b) as bb union all 
select * from (select '3' as c) as cc union all 
select * from (select '4' as d) as dd) 

select a.ID, 'Value'|| a.ID, b.ID 
from TEST_CTE a, TEST_CTE b 
where b.ID = (select min(c.ID) from TEST_CTE c where c.ID > a.ID) 

Ecco il set di risultati:

1 Value1 2 

2 Value2 3 

3 Value3 4 

Enjoy!

Alcuni ripensamenti.

^^^ La sintassi CTE può essere diversa in Oracle. Potrei solo eseguirlo in Teradata. Puoi sostituirlo con la tabella temporanea o correggere la sintassi per renderla compatibile con Oracle. L'istruzione select è semplice SQL vanilla che funzionerà su qualsiasi database.

^^^ Un'altra cosa da notare. Se il campo ID è numerico, potrebbe essere necessario inserirlo in CHAR per concatenarlo con "Valore".

+0

-1 Questo non funziona su Oracle. –

+0

Ho appena aggiunto alcuni commenti al mio post. –

0

La sintassi CTE può essere diversa per Oracle (l'ho eseguita in Teradata), ma ho utilizzato solo CTE per fornire dati di test, quelli 1 2 3 e 4. È possibile utilizzare invece la tabella temporanea. L'effettiva istruzione select è plain vanilla SQL e sarà presente su qualsiasi database relazionale.

Problemi correlati