PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Seleziona un insieme dinamico di colonne da una tabella e ottieni la somma per ciascuna

Questa query crea l'istruzione DML completa che stai cercando:

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;

Puoi eseguirlo separatamente o racchiudere questa query in una funzione plpgsql ed eseguire automaticamente la query con EXECUTE :

Automazione completa

Testato 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;

Chiama:

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

Resi:

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

Spiega

La difficoltà è definire il RETURN digitare per la funzione, mentre il numero e i nomi delle colonne restituite varieranno. Un dettaglio che aiuta un po':vuoi solo integer colonne.

Ho risolto questo problema formando un array di bigint (sum(int_col) restituisce bigint ). Inoltre, restituisco un array di nomi di colonne. Entrambi ordinati alfabeticamente in base al nome della colonna.

Nella chiamata di funzione ho diviso questi array con unnest() arrivando al bel formato visualizzato.

La query creata ed eseguita dinamicamente è roba avanzata. Non lasciarti confondere da più livelli di virgolette. Fondamentalmente hai EXECUTE che accetta un argomento di testo contenente la query SQL da eseguire. Questo testo, a sua volta, è fornito dalla query SQL secondaria che crea la stringa di query della query primaria.

Se è troppo in una volta o plpgsql è piuttosto nuovo per te, inizia con questa risposta correlata dove spiego le nozioni di base relative a una funzione molto più semplice e fornisco collegamenti al manuale per le caratteristiche principali.

Se prestazioni è essenziale interrogare direttamente il catalogo Postgres (pg_catalog.pg_attributes ) invece di usare lo standardizzato (ma lento) information_schema.columns . Ecco un semplice esempio con pg_attributes .