Installeer de extra module tablefunc
eenmaal per database, die de functie crosstab()
. biedt . Sinds Postgres 9.1 kunt u CREATE EXTENSION
. gebruiken daarvoor:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Verbeterde testcase
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
Eenvoudige vorm - niet geschikt voor ontbrekende kenmerken
crosstab(text)
met 1 invoerparameter:
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);
Retourneren:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Casten en hernoemen is niet nodig.
- Let op de onjuiste resultaat voor
C
:de waarde7
is ingevuld voor de eerste kolom. Soms is dit gedrag wenselijk, maar niet voor dit gebruik. - De eenvoudige vorm is ook beperkt tot exact drie kolommen in de opgegeven invoerquery:row_name , categorie , waarde . Er is geen ruimte voor extra kolommen zoals in het 2-parameter alternatief hieronder.
Veilig formulier
crosstab(text, text)
met 2 invoerparameters:
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);
Retourneren:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Let op het juiste resultaat voor
C
. -
De tweede parameter kan elke zoekopdracht zijn die één rij retourneert per attribuut overeenkomend met de volgorde van de kolomdefinitie aan het einde. Vaak wilt u verschillende kenmerken van de onderliggende tabel als volgt opvragen:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
Dat staat in de handleiding.
Aangezien u toch alle kolommen in een kolomdefinitielijst moet spellen (behalve voor vooraf gedefinieerde crosstabN()
varianten), is het doorgaans efficiënter om een korte lijst te geven in een VALUES
uitdrukking zoals gedemonstreerd:
$$VALUES ('Active'::text), ('Inactive')$$)
Of (niet in de handleiding):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
Ik gebruikte dollarcitaten om citeren gemakkelijker te maken.
-
U kunt zelfs kolommen uitvoeren met verschillende gegevenstypen met
crosstab(text, text)
- zolang de tekstweergave van de waardekolom geldige invoer is voor het doeltype. Op deze manier kunt u attributen van verschillende aard hebben entext
uitvoeren ,date
,numeric
enz. voor respectieve attributen. Er is een codevoorbeeld aan het einde van het hoofdstukcrosstab(text, text)
in de handleiding.
db<>viool hier
Effect van overtollige invoerrijen
Overtollige invoerrijen worden anders behandeld - dubbele rijen voor dezelfde ("rijnaam", "categorie") combinatie - (section, status)
in het bovenstaande voorbeeld.
De 1-parameter formulier vult beschikbare waardekolommen van links naar rechts in. Overtollige waarden worden weggegooid.
Vroeger ingevoerde rijen winnen.
De 2-parameter formulier wijst elke invoerwaarde toe aan de daarvoor bestemde kolom, waarbij eerdere toewijzingen worden overschreven.
Latere invoerrijen winnen.
Normaal gesproken heb je om te beginnen geen duplicaten. Maar als je dat doet, pas dan de sorteervolgorde zorgvuldig aan je eisen aan - en documenteer wat er gebeurt.
Of krijg snel willekeurige resultaten als het je niet kan schelen. Wees je bewust van het effect.
Geavanceerde voorbeelden
-
Draaien op meerdere kolommen met Tablefunc - demonstreert ook de genoemde "extra kolommen"
-
Dynamisch alternatief voor draaien met CASE en GROUP BY
\crosstabview
in psql
Postgres 9,6 heeft deze meta-opdracht toegevoegd aan de standaard interactieve terminal psql. U kunt de query uitvoeren die u zou gebruiken als eerste crosstab()
parameter en voer het naar \crosstabview
(direct of in de volgende stap). Vind ik leuk:
db=> SELECT section, status, ct FROM tbl \crosstabview
Vergelijkbaar resultaat als hierboven, maar het is een weergavefunctie aan de clientzijde uitsluitend. Invoerrijen worden iets anders behandeld, vandaar ORDER BY
is niet nodig. Details voor \crosstabview
in de handleiding. Er zijn meer codevoorbeelden onderaan die pagina.
Gerelateerd antwoord op dba.SE door Daniel Vérité (de auteur van de psql-functie):
- Hoe genereer ik een gedraaide CROSS JOIN waarvan de resulterende tabeldefinitie onbekend is?