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

Seleccione un conjunto dinámico de columnas de una tabla y obtenga la suma para cada

Esta consulta crea la instrucción DML completa que busca:

WITH x AS (
   SELECT 'public'::text     AS _schema  -- provide schema name ..
         ,'somereport'::text AS _tbl     -- .. and table name once
   )
SELECT 'SELECT ' || string_agg('sum(' || quote_ident(column_name)
                 || ') AS sum_' || quote_ident(column_name), ', ')
       || E'\nFROM   ' || quote_ident(x._schema) || '.' || quote_ident(x._tbl)
FROM   x, information_schema.columns
WHERE  table_schema = _schema
AND    table_name = _tbl
AND    data_type = 'integer'
GROUP  BY x._schema, x._tbl;

Puede ejecutarlo por separado o envolver esta consulta en una función plpgsql y ejecutar la consulta automáticamente con EXECUTE :

Automatización completa

Probado con PostgreSQL 9.1.4

CREATE OR REPLACE FUNCTION f_get_sums(_schema text, _tbl text)
  RETURNS TABLE(names text[], sums bigint[]) AS
$BODY$
BEGIN

RETURN QUERY EXECUTE (
    SELECT 'SELECT ''{'
           || string_agg(quote_ident(c.column_name), ', ' ORDER BY c.column_name)
           || '}''::text[],
           ARRAY['
           || string_agg('sum(' || quote_ident(c.column_name) || ')'
                                                   , ', ' ORDER BY c.column_name)
           || ']
    FROM   '
           || quote_ident(_schema) || '.' || quote_ident(_tbl)
    FROM   information_schema.columns c
    WHERE  table_schema = _schema
    AND    table_name = _tbl
    AND    data_type = 'integer'
    );

END;
$BODY$
  LANGUAGE plpgsql;

Llamar:

SELECT unnest(names) AS name, unnest (sums) AS col_sum
FROM   f_get_sums('public', 'somereport');

Devoluciones:

   name        | col_sum
---------------+---------
 int_col1      |    6614
 other_int_col |    8364
 third_int_col | 2720642

Explicar

La dificultad es definir el RETURN type para la función, mientras que el número y los nombres de las columnas devueltas variarán. Un detalle que ayuda un poco:solo quieres integer columnas.

Resolví esto formando una matriz de bigint (sum(int_col) devuelve bigint ). Además, devuelvo una matriz de nombres de columna. Ambos ordenados alfabéticamente por nombre de columna.

En la llamada de función, dividí estas matrices con unnest() llegando al hermoso formato que se muestra.

La consulta creada y ejecutada dinámicamente es algo avanzado. No se confunda con múltiples capas de comillas. Básicamente tienes EXECUTE que toma un argumento de texto que contiene la consulta SQL para ejecutar. Este texto, a su vez, lo proporciona la consulta SQL secundaria que crea la cadena de consulta de la consulta principal.

Si esto es demasiado a la vez o plpgsql es bastante nuevo para usted, comience con esta respuesta relacionada donde explico los conceptos básicos relacionados con una función mucho más simple y proporciono enlaces al manual para las funciones principales.

Si rendimiento es imprescindible consultar directamente el catálogo de Postgres (pg_catalog.pg_attributes ) en lugar de usar el information_schema.columns estandarizado (pero lento) . Aquí hay un ejemplo simple con pg_attributes .