sql >> Base de Datos >  >> RDS >> PostgreSQL

PostgreSQL 9.3:tabla dinámica dinámica

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.