Nainstalujte přídavný modul tablefunc
jednou na databázi, která poskytuje funkci crosstab()
. Od Postgres 9.1 můžete použít CREATE EXTENSION
za to:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Vylepšený testovací případ
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
Jednoduchý formulář – nehodí se pro chybějící atributy
crosstab(text)
s 1 vstupní parametr:
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);
Vrátí:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Není potřeba casting a přejmenování.
- Všimněte si nesprávného výsledek pro
C
:hodnota7
se vyplňuje pro první sloupec. Někdy je toto chování žádoucí, ale ne pro tento případ použití. - Jednoduchý formulář je také omezen na přesně tři sloupce v poskytnutém vstupním dotazu:název_řádku , kategorie , hodnota . Není zde místo pro sloupce navíc jako v níže uvedené 2parametrové alternativě.
Bezpečný formulář
crosstab(text, text)
s 2 vstupní parametry:
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);
Vrátí:
Section | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Poznamenejte si správný výsledek pro
C
. -
Druhý parametr může být jakýkoli dotaz, který vrací jeden řádek za atribut odpovídající pořadí definice sloupce na konci. Často budete chtít dotazovat odlišné atributy ze základní tabulky takto:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
To je v návodu.
Protože stejně musíte hláskovat všechny sloupce v seznamu definic sloupců (kromě předdefinovaných crosstabN()
varianty), je obvykle efektivnější poskytnout krátký seznam v VALUES
výraz jako předvedený:
$$VALUES ('Active'::text), ('Inactive')$$)
Nebo (není v návodu):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
Použil jsem dolarové kotace aby bylo citování jednodušší.
-
Můžete dokonce vytisknout sloupce s různými datové typy s
crosstab(text, text)
- pokud je textová reprezentace sloupce hodnot platným vstupem pro cílový typ. Tímto způsobem můžete mít atributy různého druhu a výstuptext
,date
,numeric
atd. pro příslušné atributy. Na konci kapitoly je příklad kóducrosstab(text, text)
v návodu.
db<>zde hrajte
Účinek nadbytečných vstupních řádků
S přebytečnými vstupními řádky se zachází jinak – duplicitní řádky pro stejnou kombinaci („název_řádku“, „kategorie“) – (section, status)
ve výše uvedeném příkladu.
1 parametr formulář vyplní dostupné sloupce hodnot zleva doprava. Přebytečné hodnoty jsou zahozeny.
Vyhrávají dřívější vstupní řádky.
2parametr formulář přiřadí každou vstupní hodnotu jejímu vyhrazenému sloupci a přepíše jakékoli předchozí přiřazení.
Pozdější vstupní řádky vítězí.
Obvykle pro začátek nemáte duplikáty. Ale pokud tak učiníte, pečlivě upravte pořadí řazení podle svých požadavků – a zdokumentujte, co se děje.
Nebo získejte rychlé libovolné výsledky, pokud vás to nezajímá. Jen si uvědomte účinek.
Pokročilé příklady
-
Pivot on Multiple Columns pomocí Tablefunc – také demonstruje zmíněné „extra sloupce“
-
Dynamická alternativa k pivotu s CASE a GROUP BY
\crosstabview
v psql
Postgres 9.6 přidal tento meta-příkaz do svého výchozího interaktivního terminálu psql. Můžete spustit dotaz, který byste použili jako první crosstab()
a vložte jej do \crosstabview
(ihned nebo v dalším kroku). Jako:
db=> SELECT section, status, ct FROM tbl \crosstabview
Podobný výsledek jako výše, ale jedná se o funkci reprezentace na straně klienta výhradně. Vstupní řádky jsou zpracovány mírně odlišně, proto ORDER BY
není nutné. Podrobnosti pro \crosstabview
v návodu. V dolní části této stránky jsou další příklady kódu.
Související odpověď na dba.SE od Daniela Véritého (autora funkce psql):
- Jak vygeneruji pivotované CROSS JOIN, kde výsledná definice tabulky není známa?