Weiß jemand, wie man Kreuztabellenabfragen in PostgreSQL erstellt?
Zum Beispiel habe ich die folgende Tabelle:
Section Status Count
A Active 1
A Inactive 2
B Active 4
B Inactive 5
Ich möchte, dass die Abfrage die folgende Kreuztabelle zurückgibt:
Section Active Inactive
A 1 2
B 4 5
Ist das möglich?
Antworten:
Installieren Sie das zusätzliche Modul
tablefunc
einmal pro Datenbank, die die Funktion bereitstelltcrosstab()
. Seit Postgres 9.1 können Sie dafür verwendenCREATE EXTENSION
:Verbesserter Testfall
Einfache Form - nicht für fehlende Attribute geeignet
crosstab(text)
mit 1 Eingabeparameter:Kehrt zurück:
C
: Der Wert7
wird für die erste Spalte ausgefüllt. Manchmal ist dieses Verhalten wünschenswert, aber nicht für diesen Anwendungsfall.Sichere Form
crosstab(text, text)
mit 2 Eingabeparametern:Kehrt zurück:
Notieren Sie das richtige Ergebnis für
C
.Der zweite Parameter kann eine beliebige Abfrage sein, die eine Zeile pro Attribut zurückgibt , die der Reihenfolge der Spaltendefinition am Ende entspricht. Oft möchten Sie unterschiedliche Attribute aus der zugrunde liegenden Tabelle wie folgt abfragen:
Das steht im Handbuch.
Da Sie ohnehin alle Spalten in einer Spaltendefinitionsliste buchstabieren müssen (mit Ausnahme vordefinierter Varianten), ist es in der Regel effizienter, eine kurze Liste in einem Ausdruck wie dem folgenden bereitzustellen :
crosstabN()
VALUES
Oder (nicht im Handbuch):
Ich habe Dollarnotierungen verwendet , um die Notierung zu vereinfachen.
Sie können sogar Spalten mit unterschiedlichen Ausgaben ausgeben Datentypen mit
crosstab(text, text)
- solange die Textdarstellung der Wertespalte eine gültige Eingabe für den Zieltyp ist. Auf diese Weise haben Sie vielleicht Attribute verschiedener Art und Ausgangtext
,date
,numeric
usw. für die jeweiligen Attribute. Am Ende des Kapitelscrosstab(text, text)
des Handbuchs befindet sich ein Codebeispiel .db <> hier fummeln
Fortgeschrittene Beispiele
Mit Tablefunc auf mehrere Spalten schwenken - auch die erwähnten "zusätzlichen Spalten" werden demonstriert.
Dynamische Alternative zum Pivot mit CASE und GROUP BY
\crosstabview
in psqlPostgres 9.6 hat diesen Meta-Befehl zu seinem interaktiven Standardterminal hinzugefügt psql . Sie können die Abfrage, die Sie als ersten
crosstab()
Parameter verwenden würden, ausführen und an sie weiterleiten\crosstabview
(sofort oder im nächsten Schritt). Mögen:Ähnliches Ergebnis wie oben, aber es ist ein ausschließlich auf der Client-Seite . Eingabezeilen werden geringfügig anders behandelt und sind daher
ORDER BY
nicht erforderlich. Details dazu\crosstabview
im Handbuch. Weitere Codebeispiele finden Sie am Ende dieser Seite.Verwandte Antwort auf dba.SE von Daniel Vérité (dem Autor der psql-Funktion):
Das zuvor akzeptierte Antwort ist veraltet.
Die Variante der Funktion
crosstab(text, integer)
ist veraltet. Der zweiteinteger
Parameter wird ignoriert. Ich zitiere die aktuelle Handbuch :Unnötiges Casting und Umbenennen.
Es schlägt fehl, wenn eine Zeile nicht alle Attribute enthält. Siehe sichere Variante mit zwei Eingabeparametern oben, um fehlende Attribute richtig zu behandeln.
ORDER BY
wird in der Ein-Parameter-Form von benötigtcrosstab()
.Das Handbuch:quelle
In practice the SQL query should always specify ORDER BY 1,2 to ensure that the input rows are properly ordered
Sie können die
crosstab()
Funktion des Zusatzmoduls tablefunc verwenden, das Sie einmal pro Datenbank installieren müssen . Seit PostgreSQL 9.1 können Sie dafür Folgendes verwendenCREATE EXTENSION
:In Ihrem Fall würde es ungefähr so aussehen:
quelle
quelle
sum()
, es wäre besser,min()
odermax()
und nein zu verwenden,ELSE
was auch funktionierttext
. Dies hat jedoch subtil andere Auswirkungen als diecorosstab()
, bei der nur der "erste" Wert pro Attribut verwendet wird. Es spielt keine Rolle, solange es nur einen geben kann. Schließlich ist auch die Leistung relevant.crosstab()
ist in C geschrieben und für die Aufgabe optimiert.ERROR: 42803: aggregate function calls may not be nested
Lösung mit JSON-Aggregation:
quelle
Es tut mir leid, dass dies nicht vollständig ist, da ich es hier nicht testen kann, aber es kann Sie in die richtige Richtung bringen. Ich übersetze von etwas, das ich verwende und das eine ähnliche Abfrage macht:
Der Code, mit dem ich arbeite, lautet:
Dies gibt eine typeID, das höchste Preisgebot und den niedrigsten geforderten Preis sowie die Differenz zwischen den beiden zurück (eine positive Differenz würde bedeuten, dass etwas für weniger gekauft werden könnte, als es verkauft werden kann).
quelle
Crosstab
Funktion ist unter dertablefunc
Erweiterung verfügbar . Sie müssen diese Erweiterung einmal für die Datenbank erstellen.ERWEITERUNG ERSTELLEN
tablefunc
;Mit dem folgenden Code können Sie eine Pivot-Tabelle mithilfe der Kreuztabelle erstellen:
quelle