2017-09-18 12 views
0

J'ai un tas de table qui ont une colonne (stat pour l'état ;-)résultat poignée lorsque SQL dynamique est dans une boucle

« stat » Je voudrais que le nombre de chaque stats, et vois!

Mes tableaux ressemblent à ce

create table a (
    a_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), 
    a_stat status_t 
); 
create table b (
    b_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), 
    b_stat status_t 
); 

status_t est un ENUM.

Je l'ai fait:

DO $$ 
DECLARE 
    tableName RECORD; 
    result RECORD; 
BEGIN 
    SET SEARCH_PATH = projet, public; 

    FOR tableName IN SELECT 
      c.relname, 
      a.attname 
      FROM pg_class AS c 
      INNER JOIN pg_attribute AS a ON a.attrelid = c.oid 
      WHERE a.attname LIKE '%stat' AND c.relkind = 'r' LOOP 

     EXECUTE format('SELECT %I, count(%I) FROM %I GROUP BY %I', 
        tableName.attname, tableName.attname, tableName.relname, tableName.attname) INTO result; 
     SELECT * FROM result; 
    END LOOP; 
END; 
$$; 

Il y a des choses que je pense que je ne fais pas bien ici.

  • Il est peut-être une meilleure forme format
  • Je ne peux pas sélectionner un enregistrement, je pense que le type de données n'est pas bon (mais ne peut pas savoir quel type je devrais utiliser)
  • Une sélection à l'intérieur d'une boucle for n'est pas une bonne idée (je pense?) Mais je n'ai pas trouvé comment mettre result dans un tableau de résultat, et l'afficher après la boucle for.

Comment faire cela correctement?

+0

Quel est le "nombre de chaque statistiques"? Toutes les lignes? Lignes non nulles? Autre chose? –

Répondre

0

Vous ne pouvez pas revenir d'une commande DO. Vous pouvez générer des notifications ou écrire dans une table temporaire pour contourner ce problème. Mais plutôt utiliser une fonction appropriée à la place. Comme ceci:

CREATE OR REPLACE FUNCTION foo() 
    RETURNS TABLE (sch_name text, tbl_name text, col_name text, row_count_notnull int8) AS 
$func$ 
DECLARE 
    _sch text; 
    _tbl text; 
    _col text; 
BEGIN 
    FOR _sch, _tbl, _col IN 
     SELECT n.nspname, c.relname, a.attname 
     FROM pg_class  c 
     JOIN pg_attribute a ON a.attrelid = c.oid 
     JOIN pg_namespace n ON n.oid = c.relnamespace 
     WHERE c.relnamespace = ANY ('{projet, public}'::regnamespace[]) -- projet? project? 
     AND c.relkind = 'r' 
     AND a.attname LIKE '%\_stat' -- a_stat, b_stat 
    LOOP 
     RETURN QUERY EXECUTE format(
     'SELECT $1, $2, $3, count(%I) FROM %I.%I GROUP BY 1' 
     , _col, _sch, _tbl) 
     USING _sch, _tbl, _col; 
    END LOOP; 
END 
$func$ LANGUAGE plpgsql; 

Appel:

SELECT * FROM foo(); 

points majeurs:

  • Vous ne pouvez pas SELECT sans cible ( SELECT * FROM result; ), ni dans une commande DO, ni dans un plpgsql fonction. (Vous pourriez dans une fonction SQL simple, mais vous n'avez pas de boucle là.) Je retourne les résultats avec RETURN QUERY EXECUTE.

  • En passant valeurs avec la clause USING à EXECUTE.

  • Tables qualifiant le schéma dans la requête dynamique. Sinon, vous pourriez interroger la mauvaise table par accident.

  • N'inclut pas le schéma temporaire comme votre tentative (même si vous n'êtes pas au courant).Vous pouvez l'ajouter à l'aide pg_my_temp_schema() si vous voulez, mais vous ne voulait probablement pas de toute façon:

connexes:

Il existe de nombreux autres exemples de SQL dynamique dans PLPGSQL ici. Try a search.

+0

Merci, je me demandais si je pouvais faire un select à la fin de la boucle, mais votre solution avec une fonction appropriée semble bien, merci –