2009-05-20 16 views
5

Wir haben eine Tabelle, die die folgende Form hat:einzelnen SQL-SELECT Zurückgeben mehrere Zeilen von einer Tabellenzeile

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

Wir müssen diese in zu transformieren.

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

Gibt es eine clevere Möglichkeit, dies in einer SELECT-Anweisung (d. H. Ohne UNIONs) zu tun? Die Spaltennamen Value1, Value2 und Value3 sind fest und konstant.

Die Datenbank ist Oracle 9i.

+0

Welchen DB Server benutzen Sie? –

+0

Sind 1,2,3,4 Spalten oder Datenwerte? –

+1

Der cleverste Weg, an den ich denken kann, ist, Ihre Datenbank so zu ändern, dass sie normalisiert wird :) –

Antwort

3

Dies funktioniert auf 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 

denke ich, Oracle 9i rekursive Abfragen hatte? Wie auch immer, ich bin mir ziemlich sicher, dass es CASE-Unterstützung hat, also selbst wenn es keine rekursiven Abfragen gibt, können Sie einfach "(wählen Sie 1 von Dual Union alle wählen 2 aus Dual Union alle wählen 3 aus Dual)". Der Missbrauch rekursiver Abfragen ist etwas allgemeiner - für Oracle. (Die Verwendung von Unionen zum Generieren von Zeilen ist jedoch portabel für andere DBs.)

+0

+1 für den Einzeltisch-Scan. WRT-rekursive Abfragen - Oracle hatte seit 7 hierarchische Abfragen, führte jedoch nur die rekursive WITH-Klausel in 11gR2 ein. –

9

Geben Sie eine union eine Aufnahme.

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 

union all Verwendung bedeutet, dass der Server nicht eine distinct zuführen (die in union Operationen impliziert ist). Es sollte keinen Unterschied zu den Daten machen (da Ihre IDs HOFFNUNGSVOLL sein sollten), aber es könnte etwas schneller werden.

+0

Schön, so würde ich es machen - ich mag die UNION ALL-Optimierung. Kleiner Fehler - im Beispiel gibt es keinen Wert4. Ich denke, eine alternative Möglichkeit besteht darin, zu entpivotieren, abhängig davon, ob die DB diese Funktionalität unterstützt. – RichardOD

+0

Die Verwendung von 'Union all' wird definitiv keinen Unterschied in der Ausgabe machen, da 'Value1', 'Value2' und 'Value3' alle verschieden sind! Aber es wird vermeiden, dass die DB nutzlos versucht, die Zeilen zu unifizieren. – araqnid

+0

Gute Antwort, aber Frage nach einem Weg * ohne * Gewerkschaften gefragt! –

2

Sie können es so machen, aber es ist nicht schön:

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 drei select-Anweisungen sollte es tun:

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

Wenn Sie SQL Server verwenden 2005+ Sie dann können 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

für SQL Server, betrachten UNPIVOT als Alternative zu UNION:

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

Dies wird auch den Spaltennamen zurückgeben. Ich bin mir nicht sicher, wofür das X verwendet wird, aber Sie können es nicht auslassen.

0

Eine UNION ALL, wie von anderen vorgeschlagen, ist wahrscheinlich die beste Wahl in SQL. Vielleicht möchten Sie auch daran denken, dies im Frontend zu behandeln, je nachdem, was Ihre spezifischen Anforderungen sind.

-1

Versuchen Sie Folgendes:

CTE erstellt eine temporäre Tabelle mit 4 Werten. Sie können dies so ausführen, wie es in einer Datenbank ist.

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) 

Hier ist das Ergebnis Satz:

1 Value1 2 

2 Value2 3 

3 Value3 4 

Viel Spaß!

Einige Nacherzählungen.

^^^ CTE-Syntax kann in Oracle anders sein. Ich konnte es nur in Teradata laufen lassen. Sie können es durch eine temporäre Tabelle ersetzen oder die Syntax korrigieren, um Oracle kompatibel zu machen. Die Select-Anweisung ist Plain-Vanilla-SQL, das in jeder Datenbank funktioniert.

^^^ Eine andere Sache zu beachten. Wenn das ID-Feld numerisch ist, müssen Sie es möglicherweise in CHAR umwandeln, um es mit "Value" zu verketten.

+0

-1 Dies läuft nicht auf Oracle. –

+0

Ich habe meinem Beitrag gerade einige Kommentare hinzugefügt. –

0

CTE-Syntax kann für Oracle unterschiedlich sein (ich habe es in Teradata ausgeführt), aber ich habe nur CTE verwendet, um Testdaten zu liefern, diese 1 2 3 und 4. Sie können stattdessen temporäre Tabelle verwenden. Die eigentliche Select-Anweisung ist Plain-Vanilla-SQL und wird in jeder relationalen Datenbank verwendet.

Verwandte Themen