Puedes hacer esto con crosstab()
del 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);
Si NULL
en lugar de 0
también funciona, puede ser simplemente SELECT *
en la consulta externa.
Explicación detallada:
- Consulta de tabulación cruzada de PostgreSQL
La "dificultad" especial aquí:ningún "valor" real. Entonces agrega 1 AS val
como última columna.
Número desconocido de categorías
Una consulta completamente dinámica (con tipo de resultado desconocido) no es posible en una sola consulta. Necesitas dos consultas Primero construya una declaración como la anterior dinámicamente, luego ejecútela. Detalles:
-
Seleccionando múltiples valores max() usando una sola instrucción SQL
-
¿PostgreSQL convierte columnas en filas? ¿Transponer?
-
Genere dinámicamente columnas para tabulaciones cruzadas en PostgreSQL
-
Alternativa dinámica al pivote con CASE y GROUP BY
Demasiadas categorías
Si excede el número máximo de columnas (1600), una tabulación cruzada clásica es imposible, porque el resultado no se puede representar con columnas individuales. (Además, los ojos humanos difícilmente podrían leer una tabla con tantas columnas)
Matrices o tipos de documentos como hstore
o jsonb
son la alternativa. Aquí hay una solución con matrices:
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;
-
Construye la grilla completa de valores con:
(SELECT DISTINCT colb FROM matrix) b CROSS JOIN (SELECT DISTINCT cola FROM matrix) a
-
LEFT JOIN
combinaciones existentes, ordenar por la parte numérica del nombre y agregar en matrices.right(colb, -1)::int
recorta el carácter principal de 'A3' y convierte los dígitos en enteros para obtener un orden de clasificación adecuado.
Matriz básica
Si solo quieres una tabla de 0
un 1
donde x = y
, esto se puede conseguir más 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;
Violín SQL basándose en el que proporcionaste en los comentarios.
Tenga en cuenta que sqlfiddle.com actualmente tiene un error que elimina la visualización de valores de matriz. Así que envío a text
allí para solucionarlo.