sql >> Database teknologi >  >> RDS >> PostgreSQL

PostgreSQL 9.3:Dynamisk pivottabel

Du kan gøre dette med crosstab() fra det ekstra modul 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);

Hvis NULL i stedet for 0 virker også, det kan bare være SELECT * i den ydre forespørgsel.
Detaljeret forklaring:

  • PostgreSQL krydstabulatorforespørgsel

Den særlige "besvær" her:ingen egentlig "værdi". Så tilføj 1 AS val som sidste kolonne.

Ukendt antal kategorier

En fuldstændig dynamisk forespørgsel (med ukendt resultattype) er ikke mulig i en enkelt forespørgsel. Du skal bruge to forespørgsler. Byg først en sætning som ovenstående dynamisk, og kør den derefter. Detaljer:

  • Valg af flere max()-værdier ved hjælp af en enkelt SQL-sætning

  • PostgreSQL konvertere kolonner til rækker? Transponere?

  • Generer dynamisk kolonner til krydstabeller i PostgreSQL

  • Dynamisk alternativ til pivotering med CASE og GROUP BY

For mange kategorier

Hvis du overskrider det maksimale antal kolonner (1600), er en klassisk krydstabel umulig, fordi resultatet ikke kan repræsenteres med individuelle kolonner. (Også, menneskelige øjne ville næppe kunne læse en tabel med så mange kolonner)

Arrays eller dokumenttyper såsom hstore eller jsonb er alternativet. Her er en løsning med arrays:

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;
  • Byg det komplette gitter af værdier med:

                (SELECT DISTINCT colb FROM matrix) b
    CROSS  JOIN (SELECT DISTINCT cola FROM matrix) a
    
  • LEFT JOIN eksisterende kombinationer, sorter efter den numeriske del af navnet og aggregér i arrays.

    • right(colb, -1)::int trimmer det førende tegn fra 'A3' og kaster cifrene til heltal, så vi får en korrekt sorteringsrækkefølge.

Grundlæggende matrix

Hvis du bare vil have en tabel med 0 en 1 hvor x = y , dette kan fås billigere:

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 bygger på den, du har angivet i kommentarerne.

Bemærk, at sqlfiddle.com i øjeblikket har en fejl, der dræber visningen af ​​array-værdier. Så jeg caster til text der for at omgå det.




  1. Hvordan kan jeg beskytte MySQL brugernavn og adgangskode mod dekompilering?

  2. Beregn forskel mellem to datotider i MySQL

  3. Sådan importeres en Heroku PG-dump til lokal maskine

  4. Skalær UDF-inlining i SQL Server 2019