PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Selecione um conjunto dinâmico de colunas de uma tabela e obtenha a soma para cada


Essa consulta cria a instrução DML completa que você procura:
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;

Você pode executá-lo separadamente ou envolver esta consulta em uma função plpgsql e executar a consulta automaticamente com EXECUTE :

Automação total


Testado com 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;

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

Devoluções:
   name        | col_sum
---------------+---------
 int_col1      |    6614
 other_int_col |    8364
 third_int_col | 2720642

Explicar


A dificuldade é definir o RETURN type para a função, enquanto o número e os nomes das colunas retornadas variam. Um detalhe que ajuda um pouco:você só quer integer colunas.

Eu resolvi isso formando uma matriz de bigint (sum(int_col) retorna bigint ). Além disso, retorno uma matriz de nomes de colunas. Ambos classificados em ordem alfabética pelo nome da coluna.

Na chamada da função, divido esses arrays com unnest() chegando ao formato bonito exibido.

A consulta criada e executada dinamicamente é algo avançado. Não se confunda com várias camadas de citações. Basicamente você tem EXECUTE que recebe um argumento de texto contendo a consulta SQL para execução. Esse texto, por sua vez, é fornecido pela consulta SQL secundária que constrói a string de consulta da consulta primária.

Se isso for muito de uma vez ou plpgsql é bastante novo para você, comece com esta resposta relacionada onde explico o básico sobre uma função muito mais simples e forneço links para o manual dos principais recursos.

Se desempenho é essencial consultar directamente o catálogo Postgres (pg_catalog.pg_attributes ) em vez de usar o padronizado (mas lento) information_schema.columns . Aqui está um exemplo simples com pg_attributes .