it-swarm.com.de

Zeilen dynamisch in Oracle schwenken

Ich habe die folgende Oracle 10g-Tabelle mit dem Namen _kv:

select * from _kv

ID       K       V
----     -----   -----
  1      name    Bob
  1      age     30
  1      gender  male
  2      name    Susan
  2      status  married

Ich möchte meine Schlüssel mithilfe von normalem SQL (nicht PL/SQL) in Spalten umwandeln, sodass die resultierende Tabelle in etwa so aussieht:

ID       NAME    AGE    GENDER  STATUS
----     -----   -----  ------  --------
  1      Bob      30     male 
  2      Susan                   married
  • Die Abfrage sollte so viele Spalten enthalten, wie eindeutige Ks in der Tabelle vorhanden sind (es gibt nicht so viele).
  • Es gibt keine Möglichkeit vor dem Ausführen der Abfrage zu wissen, welche Spalten möglicherweise vorhanden sind.
  • Ich versuche zu vermeiden, eine erste Abfrage auszuführen, um die endgültige Abfrage programmgesteuert zu erstellen.
  • Die leeren Zellen können Nullen oder leere Zeichenfolgen sein, spielt keine Rolle.
  • Ich verwende Oracle 10g, aber eine 11g-Lösung wäre auch in Ordnung.

Es gibt viele Beispiele dafür, wann Sie wissen, wie Ihre geschwenkten Säulen heißen können, aber ich kann einfach keine generische, pendelnde Lösung für Oracle finden.

Vielen Dank!

22
ojosilva

Oracle 11g bietet eine PIVOT-Operation, die das tut, was Sie wollen.

Oracle 11g-Lösung

select * from
(select id, k, v from _kv) 
pivot(max(v) for k in ('name', 'age', 'gender', 'status')

(Hinweis: Ich habe keine Kopie von 11g, um dies zu testen, daher habe ich die Funktionalität nicht überprüft.)

Ich habe diese Lösung erhalten von: http://orafaq.com/wiki/PIVOT

EDIT - Pivot-XML-Option (auch Oracle 11g)
Anscheinend gibt es auch eine pivot xml-Option, wenn Sie nicht alle möglichen Spaltenüberschriften kennen, die Sie möglicherweise benötigen. (Siehe den Abschnitt XML TYPE am unteren Rand der Seite unter http://www.Oracle.com/technetwork/articles/sql/11g-pivot-097235.html ).

select * from
(select id, k, v from _kv) 
pivot xml (max(v)
for k in (any) )

(Hinweis: Wie zuvor habe ich keine Kopie von 11g, um dies zu testen, damit ich die Funktionalität nicht überprüft habe.)

Edit2:v in den pivot- und pivot xml-Anweisungen in max(v) geändert, da es wie in einem Kommentar erwähnt aggregiert werden soll. Ich habe auch die in-Klausel hinzugefügt, die für pivot nicht optional ist. Wenn Sie die Werte in der in-Klausel angeben müssen, ist das Ziel einer vollständig dynamischen Pivot-/Kreuztabellenabfrage natürlich nicht erforderlich, wie dies in diesem Poster gewünscht wurde. 

29
dave

Für Situationen, in denen mehrere Werte möglich sind (in Ihrem Beispiel v), verwende ich PIVOT und LISTAGG:

SELECT * FROM
(
  SELECT id, k, v
  FROM _kv 
)
PIVOT 
(
  LISTAGG(v ,',') 
  WITHIN GROUP (ORDER BY k) 
  FOR k IN ('name', 'age','gender','status')
)
ORDER BY id;

Da Sie dynamische Werte wünschen, verwenden Sie dynamisches SQL und übergeben Sie die Werte, die durch Ausführen eines select für die Tabellendaten bestimmt wurden, bevor Sie die Pivot-Anweisung aufrufen.

6
eniacAvenger

Zufällig eine Aufgabe auf Pivot zu haben. Unten funktioniert das bei mir gerade getestet auf 11g:

select * from
(
  select ID, COUNTRY_NAME, TOTAL_COUNT from ONE_TABLE 
) 
pivot(
  SUM(TOTAL_COUNT) for COUNTRY_NAME in (
    'Canada', 'USA', 'Mexico'
  )
);
5
Herbert Yu

Zunächst muss das dynamische Pivotieren mit pivot xml erneut analysiert werden. Wir haben einen anderen Weg, dies zu tun, indem wir die Spaltennamen in einer Variablen speichern und sie wie unten in der dynamischen SQL-Klasse übergeben.

Stellen Sie sich vor, wir haben eine Tabelle wie unten.

 enter image description here

Wenn wir die Werte in der Spalte YR als Spaltennamen und die Werte in diesen Spalten von QTY anzeigen müssen, können wir den folgenden Code verwenden.

declare
  sqlqry clob;
  cols clob;
begin
  select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR)
  into   cols
  from   (select distinct YR from EMPLOYEE);


  sqlqry :=
  '      
  select * from
  (
      select *
      from EMPLOYEE
  )
  pivot
  (
    MIN(QTY) for YR in (' || cols  || ')
  )';

  execute immediate sqlqry;
end;
/

ERGEBNIS 

 enter image description here

1
Sarath Avanavu