Můžete to udělat pomocí crosstab()
z přídavného modulu tablefunc:
SELECT b
, COALESCE(a1, 0) AS "A1"
, COALESCE(a2, 0) AS "A2"
, COALESCE(a3, 0) AS "A3"
, ... -- all the way up to "A30"
FROM crosstab(
'SELECT colb, cola, 1 AS val FROM matrix
ORDER BY 1,2'
, $$SELECT 'A'::text || g FROM generate_series(1,30) g$$
) AS t (b text
, a1 int, a2 int, a3 int, a4 int, a5 int, a6 int
, a7 int, a8 int, a9 int, a10 int, a11 int, a12 int
, a13 int, a14 int, a15 int, a16 int, a17 int, a18 int
, a19 int, a20 int, a21 int, a22 int, a23 int, a24 int
, a25 int, a26 int, a27 int, a28 int, a29 int, a30 int);
Pokud NULL
místo 0
funguje také, může to být jen SELECT *
ve vnějším dotazu.
Podrobné vysvětlení:
- PostgreSQL Crosstab Query
Zvláštní "obtížnost" zde:žádná skutečná "hodnota". Přidejte tedy 1 AS val
jako poslední sloupec.
Neznámý počet kategorií
Zcela dynamický dotaz (s neznámým typem výsledku) není možný v jediném dotazu. Potřebujete dva dotazy. Nejprve dynamicky vytvořte příkaz, jako je výše uvedený, a poté jej proveďte. Podrobnosti:
-
Výběr více hodnot max() pomocí jednoho příkazu SQL
-
PostgreSQL převést sloupce na řádky? Transponovat?
-
Dynamicky generujte sloupce pro křížové tabulky v PostgreSQL
-
Dynamická alternativa k pivotu s CASE a GROUP BY
Příliš mnoho kategorií
Při překročení maximálního počtu sloupců (1600) je klasická kontingenční tabulka nemožná, protože výsledek nelze reprezentovat jednotlivými sloupci. (Také lidské oči by stěží dokázaly přečíst tabulku s tolika sloupci)
Pole nebo typy dokumentů, jako je hstore
nebo jsonb
jsou alternativou. Zde je řešení s poli:
SELECT colb, array_agg(cola) AS colas
FROM (
SELECT colb, right(colb, -1)::int AS sortb
, CASE WHEN m.cola IS NULL THEN 0 ELSE 1 END AS cola
FROM (SELECT DISTINCT colb FROM matrix) b
CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
LEFT JOIN matrix m USING (colb, cola)
ORDER BY sortb, right(cola, -1)::int
) sub
GROUP BY 1, sortb
ORDER BY sortb;
-
Sestavte úplnou mřížku hodnot pomocí:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
-
LEFT JOIN
existující kombinace, seřadit podle číselné části názvu a agregovat do polí.right(colb, -1)::int
ořízne úvodní znak z „A3“ a převede číslice na celé číslo, abychom získali správné pořadí řazení.
Základní matice
Pokud chcete pouze tabulku 0
1
kde x = y
, to může být levnější:
SELECT x, array_agg((x = y)::int) AS y_arr
FROM generate_series(1,10) x
, generate_series(1,10) y
GROUP BY 1
ORDER BY 1;
SQL Fiddle navazuje na ten, který jste uvedli v komentářích.
Všimněte si, že sqlfiddle.com aktuálně obsahuje chybu, která zastavuje zobrazení hodnot pole. Takže jsem přetypoval na text
tam to obejít.