Installa il modulo aggiuntivo tablefunc
una volta per database, che fornisce la funzione crosstab()
. Da Postgres 9.1 puoi usare CREATE EXTENSION
per questo:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Caso 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 gli 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);
Ritorna:
Sezione | Attivo | Inattivo
--------- + -------- + ----------
A | 1 | 2
B | 4 | 5
C | 7 | - !!
- Non è necessario il cast e la ridenominazione.
- Nota il risultato errato per
C
: il valore 7
viene inserito per la prima colonna. A volte, questo comportamento è desiderabile, ma non per questo caso d'uso.
- Il modulo semplice è inoltre limitato a esattamente tre colonne nella query di input fornita: row_name , categoria , valore . Non c'è spazio per colonne extra come nell'alternativa a 2 parametri di seguito.
Forma sicura
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);
Ritorna:
Sezione | Attivo | Inattivo
--------- + -------- + ----------
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 corrispondente 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'
Questo è nel manuale.
Dato che devi comunque precisare tutte le colonne in un elenco di definizioni di colonne (tranne che per le varianti predefinite ), è in genere più efficiente fornire un breve elenco in un'espressione come dimostrato:crosstabN()
VALUES
$$VALUES ('Active'::text), ('Inactive')$$)
Oppure (non nel manuale):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
Ho usato la quotazione in dollari per semplificare la quotazione.
Si può anche colonne di output con diversi tipi di dati con crosstab(text, text)
- fino a quando la rappresentazione del testo della colonna di valore è di input valido per il tipo di destinazione. In questo modo si potrebbe avere gli attributi di diverso tipo e in uscita text
, date
, numeric
ecc per rispettivi attributi. C'è un esempio di codice alla fine del capitolo crosstab(text, text)
nel manuale .
db <> violino qui
Esempi avanzati
\crosstabview
in psql
Postgres 9.6 ha aggiunto questo meta-comando al suo terminale interattivo psql predefinito . È possibile eseguire la query da utilizzare come primo crosstab()
parametro e alimentarla \crosstabview
(immediatamente o nel passaggio successivo). Piace:
db=> SELECT section, status, ct FROM tbl \crosstabview
Risultato simile a quello sopra, ma è esclusivamente una funzione di rappresentazione sul lato client . Le righe di input vengono trattate in modo leggermente diverso, quindi ORDER BY
non è necessario. 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):
La risposta precedentemente accettata è obsoleta.
La variante della funzione crosstab(text, integer)
è obsoleta. Il secondo integer
parametro viene ignorato. Cito il manuale attuale :
crosstab(text sql, int N)
...
Versione obsoleta di crosstab(text)
. Il parametro N
è ora ignorato, poiché il numero di colonne di valori è sempre determinato dalla query chiamante
Inutili casting e ridenominazioni.
Non riesce se una riga non ha tutti gli attributi. Vedere la variante sicura con due parametri di input sopra per gestire correttamente gli attributi mancanti.
ORDER BY
è richiesto nella forma di un parametro di crosstab()
. Il manuale:
In pratica, la query SQL deve sempre specificare ORDER BY 1,2
per garantire che le righe di input siano ordinate correttamente