Você pode fazer isso com
crosstab()
do módulo adicional 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
em vez de 0
funciona também, pode ser apenas SELECT *
na consulta externa.Explicação detalhada:
- Consulta de tabela cruzada PostgreSQL
A "dificuldade" especial aqui:nenhum "valor" real. Então adicione
1 AS val
como última coluna. Número desconhecido de categorias
Uma consulta completamente dinâmica (com tipo de resultado desconhecido) não é possível em uma única consulta. Você precisa de dois consultas. Primeiro construa uma instrução como a acima dinamicamente, depois execute-a. Detalhes:
-
Selecionando vários valores max() usando uma única instrução SQL
-
PostgreSQL converte colunas em linhas? Transpor?
-
Gerar colunas dinamicamente para crosstab no PostgreSQL
-
Alternativa dinâmica para pivotar com CASE e GROUP BY
Demasiadas categorias
Se você exceder o número máximo de colunas (1600), uma tabela cruzada clássica é impossível, porque o resultado não pode ser representado com colunas individuais. (Além disso, os olhos humanos dificilmente seriam capazes de ler uma tabela com tantas colunas)
Arrays ou tipos de documentos como
hstore
ou jsonb
são a alternativa. Aqui está uma solução com 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;
-
Construa a grade completa de valores com:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
-
LEFT JOIN
combinações existentes, ordenar pela parte numérica do nome e agregar em arrays.
right(colb, -1)::int
corta o caractere inicial de 'A3' e converte os dígitos em inteiro para obtermos uma ordem de classificação adequada.
Matriz básica
Se você quer apenas uma tabela de
0
um 1
onde x = y
, isso pode ser mais barato: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;
Fiddle SQL com base no que você forneceu nos comentários.
Observe que sqlfiddle.com atualmente tem um bug que mata a exibição de valores de array. Então eu transmito para
text
lá para contornar isso.