Installa il modulo aggiuntivo tablefunc
una volta per database, che fornisce la funzione crosstab()
. Da Postgres 9.1 puoi usare CREATE EXTENSION
per quello:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Campo di prova migliorato
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
Modulo semplice - non adatto per attributi mancanti
crosstab(text)
con 1 parametro di input:
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);
Resi:
SezioneSection | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | 7 | -- !!
- Non c'è bisogno di casting e ridenominazione.
- Nota l'errata risultato per
C
:il valore7
viene compilato per la prima colonna. A volte, questo comportamento è desiderabile, ma non per questo caso d'uso. - Anche il modulo semplice è limitato a esattamente tre colonne nella query di input fornita:nome_riga , categoria , valore . Non c'è spazio per colonne extra come nell'alternativa a 2 parametri di seguito.
Modulo sicuro
crosstab(text, text)
con 2 parametri di input:
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);
Resi:
SezioneSection | Active | Inactive ---------+--------+---------- A | 1 | 2 B | 4 | 5 C | | 7 -- !!
-
Nota il risultato corretto per
C
. -
Il secondo parametro può essere qualsiasi query che restituisce una riga per attributo che corrisponde all'ordine della definizione di colonna alla fine. Spesso vorrai interrogare attributi distinti dalla tabella sottostante in questo modo:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
È nel manuale.
Dal momento che devi comunque precisare tutte le colonne in un elenco di definizioni di colonna (tranne per crosstabN()
varianti), in genere è più efficiente fornire un breve elenco in un VALUES
espressione come dimostrato:
$$VALUES ('Active'::text), ('Inactive')$$)
Oppure (non nel manuale):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
-
Ho usato citando il dollaro per semplificare la quotazione.
-
Puoi anche generare colonne con diverse tipi di dati con
crosstab(text, text)
- fintanto che la rappresentazione testuale della colonna del valore è un input valido per il tipo di destinazione. In questo modo potresti avere attributi di tipo diverso e produrretext
,date
,numeric
ecc. per i rispettivi attributi. C'è un esempio di codice alla fine del capitolocrosstab(text, text)
nel manuale.
db<>gioca qui
Effetto delle righe di input in eccesso
Le righe di input in eccesso vengono gestite in modo diverso:righe duplicate per la stessa combinazione ("nome_riga", "categoria") - (section, status)
nell'esempio sopra.
Il parametro 1 il modulo riempie le colonne dei valori disponibili da sinistra a destra. I valori in eccesso vengono eliminati.
Le righe di input precedenti vincono.
Il 2-parametro form assegna ogni valore di input alla sua colonna dedicata, sovrascrivendo qualsiasi assegnazione precedente.
Le righe di input successive vincono.
In genere, non hai duplicati per cominciare. Ma se lo fai, adatta con attenzione l'ordinamento in base alle tue esigenze e documenta ciò che sta accadendo.
Oppure ottieni risultati arbitrari rapidi se non ti interessa. Basta essere consapevoli dell'effetto.
Esempi avanzati
-
Ruota su più colonne utilizzando Tablefunc, dimostrando anche le "colonne extra" citate
-
Alternativa dinamica al pivot con CASE e GROUP BY
\crosstabview
in psql
Postgres 9.6 aggiunto questo meta-comando al suo terminale interattivo predefinito psql. Puoi eseguire la query che useresti come prima crosstab()
parametro e invialo a \crosstabview
(immediatamente o nel passaggio successivo). Come:
db=> SELECT section, status, ct FROM tbl \crosstabview
Risultato simile al precedente, ma è una funzione di rappresentazione lato client esclusivamente. Le righe di input sono trattate in modo leggermente diverso, quindi ORDER BY
non è richiesto. Dettagli per \crosstabview
nel manuale. Ci sono altri esempi di codice in fondo a quella pagina.
Risposta correlata su dba.SE di Daniel Vérité (l'autore della funzione psql):
- Come faccio a generare un CROSS JOIN con pivot in cui la definizione della tabella risultante è sconosciuta?