Singolo SQL SELECT multiple righe da una riga della tabella
Domanda
Abbiamo un tavolo che è della forma:
ID,Value1,Value2,Value3
1,2,3,4
Abbiamo bisogno di trasformare questo in.
ID,Name,Value
1,'Value1',2
1,'Value2',3
1,'Value3',4
C'è un modo intelligente di fare questo in un'istruzione SELECT (cioè senza UNION)? I nomi delle colonne valore1, valore2 e valore3 sono fissi e costanti.
Il database è Oracle 9i.
Soluzione
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
Credo che Oracle 9i aveva query ricorsive? Comunque, sono abbastanza sicuro che ha il supporto CASE, quindi, anche se non ha query ricorsive, si può solo fare "(selezionare 1 dalla doppia unione tutto selezionare 2 da dual union all select 3 dal doppio) OFS", invece. Abusando query ricorsive è un po 'più generale- per Oracle. (Utilizzando i sindacati per generare righe è portabile su altri DB, però)
Altri suggerimenti
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à un distinct
(che è implicito nelle operazioni union
). Non dovrebbe fare alcuna differenza con i dati (dal momento che il proprio ID di spera, dovrebbe essere diverso), ma potrebbe accelerarlo un po '.
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
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
Se si utilizza SQL Server 2005 + quindi è possibile utilizzare 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
A UNION ALL, come altri hanno suggerito, è probabilmente la soluzione migliore in SQL. Si potrebbe anche prendere in considerazione la gestione di questo, alla fine, di fronte a seconda di cosa i vostri requisiti specifici.
sintassi CTE può essere diverso per Oracle (Mi sono imbattuto in Teradata), ma ho usato solo CTE per fornire dati di test, quelli 1 2 3 e 4. È possibile utilizzare tabella temporanea, invece. La dichiarazione reale è select SQL plain vanilla e sarà su qualsiasi database relazionale.
Per SQL Server, considerare UNPIVOT come alternativa a UNION:
SELECT id, value, colname
FROM #temp t
UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X
Ciò restituirà il nome della colonna pure. Non sono sicuro che cosa la X è usato per, ma non si può lasciare fuori.
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.
^^^ CTE sintassi può essere diverso in Oracle. Potrei eseguito solo in Teradata. È possibile sostituirlo con tabella temporanea o fissare la sintassi per renderlo compatibile con Oracle. L'istruzione SELECT è SQL plain vanilla che funziona su qualsiasi database.
^^^ Un'altra cosa da notare. Se il campo ID è numerico, potrebbe essere necessario lanciare in CHAR per concatenare con "Valore".