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

Exécuter des requêtes dynamiquement en PL/pgSQL

Statistiques système

Avant de lancer le vôtre, jetez un œil à la table système pg_statistic ou la vue pg_stats :

Il peut déjà avoir certaines des statistiques que vous êtes sur le point de calculer. Il est rempli par ANALYZE , vous pouvez donc l'exécuter pour les nouvelles tables (ou toutes) avant de vérifier.

-- ANALYZE tbl;  -- optionally, to init / refresh
SELECT * FROM pg_stats
WHERE tablename = 'tbl'
AND   schemaname = 'public';

Fonction plpgsql dynamique générique

Vous souhaitez renvoyer la valeur minimale pour chaque colonne d'une table donnée . Ce n'est pas une tâche triviale, car une fonction (comme SQL en général) demande de connaître le type de retour au moment de la création - ou du moins au moment de l'appel à l'aide de types de données polymorphes.

Cette fonction fait tout automatiquement et en toute sécurité. Fonctionne pour tous table, tant que la fonction d'agrégation min() est autorisé pour chaque colonne. Mais vous avez besoin pour vous familiariser avec PL/pgSQL.

CREATE OR REPLACE FUNCTION f_min_of(_tbl anyelement)
  RETURNS SETOF anyelement
  LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE (
   SELECT format('SELECT (t::%2$s).* FROM (SELECT min(%1$s) FROM %2$s) t'
                , string_agg(quote_ident(attname), '), min(' ORDER BY attnum)
                , pg_typeof(_tbl)::text)
   FROM   pg_attribute
   WHERE  attrelid = pg_typeof(_tbl)::text::regclass
   AND    NOT attisdropped  -- no dropped (dead) columns
   AND    attnum > 0        -- no system columns
   );
END
$func$;

Appel (important !) :

SELECT * FROM f_min_of(NULL::tbl);  -- tbl being the table name

db<>violon ici
Ancien sqlfiddle

Vous devez comprendre ces concepts :

  • SQL dynamique dans plpgsql avec EXECUTE
  • Types polymorphes
  • Types de lignes et types de tables dans Postgres
  • Comment se défendre contre l'injection SQL
  • Fonctions d'agrégation
  • Catalogues système

Réponse connexe avec une explication détaillée :

Difficulté particulière avec l'incompatibilité de type

Je profite de Postgres définissant un type de ligne pour chaque table existante. En utilisant le concept de types polymorphes, je suis capable d'en créer un fonction qui fonctionne pour n'importe quelle table.

Cependant, certaines fonctions d'agrégation renvoient des types de données liés mais différents par rapport à la colonne sous-jacente. Par exemple, min(varchar_column) renvoie text , qui est compatible au niveau des bits, mais pas exactement le même type de données. Les fonctions PL/pgSQL ont un point faible ici et insistent sur les types de données exactement comme déclaré dans le RETURNS clause. Aucune tentative de cast, pas même de casts implicites, sans parler des casts d'assignation.

Cela devrait être amélioré. Testé avec Postgres 9.3. Je n'ai pas retesté avec 9.4, mais je suis presque sûr que rien n'a changé dans ce domaine.

C'est là que cette construction entre en jeu comme solution de contournement :

SELECT (t::tbl).* FROM (SELECT ... FROM tbl) t;

En convertissant explicitement la ligne entière en type de ligne de la table sous-jacente, nous forçons les transtypages d'affectation à obtenir les types de données d'origine pour chaque colonne.

Cela peut échouer pour certaines fonctions d'agrégation. sum() renvoie numeric pour une sum(bigint_column) pour tenir compte d'une somme dépassant le type de données de base. Relancer vers bigint peut échouer ...