sql >> Databáze >  >> RDS >> PostgreSQL

PostgreSQL 9.3:Dynamická kontingenční tabulka

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.




  1. Oracle – Jaký soubor TNS Names používám?

  2. Výběr databáze pro vytvoření dvou propojených tabulek?

  3. Jak odečíst 30 dní od data v T-SQL

  4. Hlášení využití možností databáze/balíčků