PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wählen Sie einen dynamischen Satz von Spalten aus einer Tabelle aus und erhalten Sie die Summe für jede Spalte

Diese Abfrage erstellt die vollständige DML-Anweisung, nach der Sie suchen:

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;

Sie können sie separat ausführen oder diese Abfrage in eine plpgsql-Funktion packen und die Abfrage automatisch mit EXECUTE ausführen :

Vollständige Automatisierung

Getestet mit 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;

Aufruf:

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

Rückgabe:

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

Erklären

Die Schwierigkeit besteht darin, den RETURN zu definieren Typ für die Funktion, während Anzahl und Namen der zurückgegebenen Spalten variieren. Ein Detail, das ein wenig hilft:Sie wollen nur integer Spalten.

Ich habe das gelöst, indem ich ein Array von bigint gebildet habe (sum(int_col) gibt bigint zurück ). Außerdem gebe ich ein Array von Spaltennamen zurück. Beide alphabetisch nach Spaltennamen sortiert.

Im Funktionsaufruf zerlege ich diese Arrays mit unnest() Ankommend bei dem ansehnlichen angezeigten Format.

Die dynamisch erstellte und ausgeführte Abfrage ist fortgeschrittenes Zeug. Lassen Sie sich nicht durch mehrere Ebenen von Anführungszeichen verwirren. Grundsätzlich haben Sie EXECUTE die ein Textargument akzeptiert, das die auszuführende SQL-Abfrage enthält. Dieser Text wiederum wird von einer sekundären SQL-Abfrage bereitgestellt, die die Abfragezeichenfolge der primären Abfrage erstellt.

Wenn das zu viel auf einmal ist oder plpgsql ziemlich neu für Sie ist, beginnen Sie mit dieser verwandten Antwort wo ich die Grundlagen erkläre, die sich mit einer viel einfacheren Funktion befassen, und Links zum Handbuch für die Hauptfunktionen bereitstelle.

Wenn Leistung unbedingt den Postgres-Katalog direkt abfragen (pg_catalog.pg_attributes ) anstatt die standardisierten (aber langsamen) information_schema.columns zu verwenden . Hier ist ein einfaches Beispiel mit pg_attributes .