PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Sélectionnez un ensemble dynamique de colonnes dans une table et obtenez la somme de chacune

Cette requête crée l'instruction DML complète que vous recherchez :

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;

Vous pouvez l'exécuter séparément ou envelopper cette requête dans une fonction plpgsql et exécuter la requête automatiquement avec EXECUTE :

Automatisation complète

Testé avec 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;

Appel :

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

Renvoie :

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

Expliquez

La difficulté est de définir le RETURN type pour la fonction, tandis que le nombre et les noms des colonnes renvoyées varient. Un détail qui aide un peu :vous ne voulez que integer colonnes.

J'ai résolu ce problème en formant un tableau de bigint (sum(int_col) renvoie bigint ). De plus, je renvoie un tableau de noms de colonnes. Les deux sont triés par ordre alphabétique par nom de colonne.

Dans l'appel de fonction, j'ai divisé ces tableaux avec unnest() arriver au beau format affiché.

La requête créée et exécutée dynamiquement est un élément avancé. Ne vous laissez pas confondre par plusieurs couches de citations. En gros, vous avez EXECUTE qui prend un argument texte contenant la requête SQL à exécuter. Ce texte, à son tour, est fourni par une requête SQL secondaire qui construit la chaîne de requête de la requête principale.

Si c'est trop à la fois ou plpgsql est plutôt nouveau pour vous, commencez par cette réponse connexe où j'explique les bases d'une fonction beaucoup plus simple et fournit des liens vers le manuel pour les principales fonctionnalités.

Si les performances est indispensable interroger directement le catalogue Postgres (pg_catalog.pg_attributes ) au lieu d'utiliser le standardisé (mais lent) information_schema.columns . Voici un exemple simple avec pg_attributes .