Installieren Sie das zusätzliche Modul tablefunc
einmal pro Datenbank, die die Funktion bereitstellt crosstab()
. Seit Postgres 9.1 können Sie dafür verwenden CREATE EXTENSION
:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Verbesserter Testfall
CREATE TABLE tbl (
section text
, status text
, ct integer -- "count" is a reserved word in standard SQL
);
INSERT INTO tbl VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7); -- ('C', 'Active') is missing
Einfache Form - nicht für fehlende Attribute geeignet
crosstab(text)
mit 1 Eingabeparameter:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
Kehrt zurück:
Abschnitt | Aktiv | Inaktiv
--------- + -------- + ----------
A | 1 | 2
B | 4 | 5
C | 7 | - !!
- Kein Casting und Umbenennen erforderlich.
- Beachten Sie das falsche Ergebnis für
C
: Der Wert 7
wird für die erste Spalte ausgefüllt. Manchmal ist dieses Verhalten wünschenswert, aber nicht für diesen Anwendungsfall.
- Das einfache Formular ist in der bereitgestellten Eingabeabfrage auch auf genau drei Spalten beschränkt : Zeilenname , Kategorie , Wert . Es ist kein Platz für zusätzliche Spalten wie in der folgenden 2-Parameter-Alternative.
Sichere Form
crosstab(text, text)
mit 2 Eingabeparametern:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- could also just be "ORDER BY 1" here
, $$VALUES ('Active'::text), ('Inactive')$$
) AS ct ("Section" text, "Active" int, "Inactive" int);
Kehrt zurück:
Abschnitt | Aktiv | Inaktiv
--------- + -------- + ----------
A | 1 | 2
B | 4 | 5
C | | 7 - !!
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:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
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
$$VALUES ('Active'::text), ('Inactive')$$)
Oder (nicht im Handbuch):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
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 Ausgang text
, date
, numeric
usw. für die jeweiligen Attribute. Am Ende des Kapitels crosstab(text, text)
des Handbuchs befindet sich ein Codebeispiel .
db <> hier fummeln
Fortgeschrittene Beispiele
\crosstabview
in psql
Postgres 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:
db=> SELECT section, status, ct FROM tbl \crosstabview
Ä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 zweite integer
Parameter wird ignoriert. Ich zitiere die aktuelle Handbuch :
crosstab(text sql, int N)
...
Veraltete Version von crosstab(text)
. Der Parameter N
wird jetzt ignoriert, da die Anzahl der Wertespalten immer von der aufrufenden Abfrage bestimmt wird
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ötigt crosstab()
.Das Handbuch:
In der Praxis sollte die SQL-Abfrage immer angeben, ORDER BY 1,2
um sicherzustellen, dass die Eingabezeilen ordnungsgemäß sortiert sind