Installera tilläggsmodulen tablefunc
en gång per databas, som tillhandahåller funktionen crosstab()
. Sedan Postgres 9.1 kan du använda CREATE EXTENSION
för det:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Förbättrat 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
Enkel form – inte lämplig för saknade attribut
crosstab(text)
med 1 ingångsparameter:
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);
Returnerar:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Inget behov av att casta och byta namn.
- Observera det felaktiga resultat för
C
:värdet7
fylls i för den första kolumnen. Ibland är detta beteende önskvärt, men inte för detta användningsfall. - Den enkla formen är också begränsad till exakt tre kolumner i den angivna inmatningsfrågan:radnamn , kategori , värde . Det finns inget utrymme för extra kolumner som i alternativet med två parametrar nedan.
Säker form
crosstab(text, text)
med 2 ingångsparametrar:
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);
Returnerar:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Notera det korrekta resultatet för
C
. -
Den andra parametern kan vara vilken fråga som helst som returnerar en rad per attribut som matchar ordningen för kolumndefinitionen i slutet. Ofta vill du fråga efter distinkta attribut från den underliggande tabellen så här:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
Det står i manualen.
Eftersom du måste stava alla kolumner i en kolumndefinitionslista ändå (förutom fördefinierade crosstabN()
varianter), är det vanligtvis mer effektivt att tillhandahålla en kort lista i en VALUES
uttryck som visas:
$$VALUES ('Active'::text), ('Inactive')$$)
Eller (inte i manualen):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
Jag använde dollarnotering för att göra det enklare att citera.
-
Du kan till och med skriva ut kolumner med olika datatyper med
crosstab(text, text)
- så länge som textrepresentationen av värdekolumnen är giltig inmatning för måltypen. På så sätt kan du ha attribut av olika slag och utdatatext
,date
,numeric
etc. för respektive attribut. Det finns ett kodexempel i slutet av kapitletcrosstab(text, text)
i manualen.
db<>spela här
Effekt av överflödiga inmatningsrader
Överflödiga inmatningsrader hanteras på olika sätt - dubbletter av rader för samma ("radnamn", "kategori") kombination - (section, status)
i exemplet ovan.
1-parametern formuläret fyller i tillgängliga värdekolumner från vänster till höger. Överskjutande värden kasseras.
Tidigare inmatningsrader vinner.
2-parametern form tilldelar varje inmatningsvärde till dess dedikerade kolumn och skriver över alla tidigare tilldelningar.
Senare inmatningsrader vinner.
Vanligtvis har du inga dubbletter till att börja med. Men om du gör det, justera noggrant sorteringsordningen efter dina krav - och dokumentera vad som händer.
Eller få snabba godtyckliga resultat om du inte bryr dig. Var bara medveten om effekten.
Avancerade exempel
-
Pivotera på flera kolumner med hjälp av Tablefunc - demonstrerar också nämnda "extra kolumner"
-
Dynamiskt alternativ att pivotera med CASE och GROUP BY
\crosstabview
i psql
Postgres 9.6 lade till detta metakommando till sin interaktiva standardterminal psql. Du kan köra frågan du skulle använda som första crosstab()
parametern och mata den till \crosstabview
(omedelbart eller i nästa steg). Gilla:
db=> SELECT section, status, ct FROM tbl \crosstabview
Liknande resultat som ovan, men det är en representationsfunktion på klientsidan uteslutande. Inmatningsrader behandlas något annorlunda, därför ORDER BY
behövs inte. Detaljer för \crosstabview
i manualen. Det finns fler kodexempel längst ner på den sidan.
Relaterat svar på dba.SE av Daniel Vérité (författaren till psql-funktionen):
- Hur skapar jag en pivoterad CROSS JOIN där den resulterande tabelldefinitionen är okänd?