Puoi farlo con crosstab()
dal modulo aggiuntivo 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);
Se NULL
invece di 0
funziona anche, può essere solo SELECT *
nella query esterna.
Spiegazione dettagliata:
- Query a campi incrociati PostgreSQL
La "difficoltà" speciale qui:nessun "valore" effettivo. Quindi aggiungi 1 AS val
come ultima colonna.
Numero sconosciuto di categorie
Una query completamente dinamica (con tipo di risultato sconosciuto) non è possibile in una singola query. Ne servono due interrogazioni. Per prima cosa costruisci un'istruzione come quella sopra in modo dinamico, quindi eseguila. Dettagli:
-
Selezione di più valori max() utilizzando una singola istruzione SQL
-
PostgreSQL converte le colonne in righe? Trasporre?
-
Genera dinamicamente colonne per campi incrociati in PostgreSQL
-
Alternativa dinamica al pivot con CASE e GROUP BY
Troppe categorie
Se si supera il numero massimo di colonne (1600), un classico campo incrociato è impossibile, perché il risultato non può essere rappresentato con singole colonne. (Inoltre, gli occhi umani difficilmente sarebbero in grado di leggere una tabella con così tante colonne)
Array o tipi di documenti come hstore
o jsonb
sono l'alternativa. Ecco una soluzione con gli array:
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;
-
Costruisci la griglia completa dei valori con:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
-
LEFT JOIN
combinazioni esistenti, ordinate in base alla parte numerica del nome e aggregate in array.right(colb, -1)::int
taglia il carattere principale da "A3" e trasforma le cifre in numeri interi in modo da ottenere un ordinamento corretto.
Matrice di base
Se vuoi solo una tabella di 0
un 1
dove x = y
, questo può essere più conveniente:
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 basandosi su quello che hai fornito nei commenti.
Nota che sqlfiddle.com ha attualmente un bug che uccide la visualizzazione dei valori dell'array. Quindi trasmetto a text
lì per aggirarlo.