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

PostgreSQL krydstabulatorforespørgsel

Installer det ekstra modul tablefunc en gang per database, som giver funktionen crosstab() . Siden Postgres 9.1 kan du bruge CREATE EXTENSION for det:

CREATE EXTENSION IF NOT EXISTS tablefunc;

Forbedret testcase

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

Simpel form - ikke egnet til manglende attributter

crosstab(text) med 1 input parameter:

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);

Returnerer:

 Section | Active | Inactive
---------+--------+----------
 A       |      1 |        2
 B       |      4 |        5
 C       |      7 |           -- !!
  • Intet behov for at caste og omdøbe.
  • Bemærk det forkerte resultat for C :værdien 7 er udfyldt for første kolonne. Nogle gange er denne adfærd ønskværdig, men ikke til denne brug.
  • Den simple form er også begrænset til præcis tre kolonner i den angivne inputforespørgsel:rækkenavn , kategori , værdi . Der er ikke plads til ekstra kolonner som i alternativet med 2 parametre nedenfor.

Sikker form

crosstab(text, text) med 2 inputparametre:

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);

Returnerer:

 Section | Active | Inactive
---------+--------+----------
 A       |      1 |        2
 B       |      4 |        5
 C       |        |        7  -- !!
  • Bemærk det korrekte resultat for C .

  • Den anden parameter kan være enhver forespørgsel, der returnerer én række attribut, der matcher rækkefølgen af ​​kolonnedefinitionen i slutningen. Ofte vil du gerne forespørge om forskellige attributter fra den underliggende tabel på denne måde:

      'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
    

Det står i manualen.

Da du alligevel skal stave alle kolonner i en kolonnedefinitionsliste (undtagen foruddefinerede crosstabN() varianter), er det typisk mere effektivt at give en kort liste i en VALUES udtryk som vist:

    $$VALUES ('Active'::text), ('Inactive')$$)

Eller (ikke i manualen):

    $$SELECT unnest('{Active,Inactive}'::text[])$$  -- short syntax for long lists
  • Jeg brugte dollarnotering for at gøre det lettere at citere.

  • Du kan endda udskrive kolonner med forskellige datatyper med crosstab(text, text) - så længe tekstrepræsentationen af ​​værdikolonnen er gyldig input for måltypen. På denne måde kan du have attributter af forskellig art og output text , date , numeric osv. for respektive attributter. Der er et kodeeksempel i slutningen af ​​kapitlet crosstab(text, text) i manualen.

db<>spil her

Effekt af overskydende inputrækker

Overskydende inputrækker håndteres forskelligt - dublerede rækker for den samme ("row_name", "category") kombination - (section, status) i ovenstående eksempel.

1-parameteren formularen udfylder tilgængelige værdikolonner fra venstre mod højre. Overskydende værdier kasseres.
Tidligere inputrækker vinder.

2-parameteren formular tildeler hver inputværdi til dens dedikerede kolonne og overskriver enhver tidligere tildeling.
Senere inputrækker vinder.

Typisk har du ikke dubletter til at begynde med. Men hvis du gør det, skal du omhyggeligt justere sorteringsrækkefølgen til dine krav - og dokumentere, hvad der sker.
Eller få hurtige vilkårlige resultater, hvis du er ligeglad. Bare vær opmærksom på effekten.

Avancerede eksempler

  • Pivot på flere kolonner ved hjælp af Tablefunc - demonstrerer også nævnte "ekstra kolonner"

  • Dynamisk alternativ til pivotering med CASE og GROUP BY


\crosstabview i psql

Postgres 9.6 tilføjede denne metakommando til dens interaktive standardterminal psql. Du kan køre den forespørgsel, du ville bruge som første crosstab() parameter og feed den til \crosstabview (umiddelbart eller i næste trin). Ligesom:

db=> SELECT section, status, ct FROM tbl \crosstabview

Tilsvarende resultat som ovenfor, men det er en repræsentationsfunktion på klientsiden udelukkende. Input rækker behandles lidt anderledes, derfor ORDER BY er ikke påkrævet. Detaljer for \crosstabview i manualen. Der er flere kodeeksempler nederst på siden.

Relateret svar på dba.SE af Daniel Vérité (forfatteren af ​​psql-funktionen):

  • Hvordan genererer jeg en pivoteret CROSS JOIN, hvor den resulterende tabeldefinition er ukendt?


  1. Finde samtidige hændelser i en database mellem tidspunkter

  2. Dvale tidsstempel med tidszone

  3. Hvad er de 6 hovedkomponenter i Microsoft Access?

  4. Neo4j - Drop et indeks ved hjælp af Cypher