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

Boucle sur les tables avec PL/pgSQL dans Postgres 9.0+

Je ne me souviens pas de la dernière fois où j'ai eu besoin d'utiliser un curseur explicite pour boucler dans plpgsql.
Utilisez le curseur implicite d'un FOR boucle, c'est beaucoup plus propre :

DO
$$
DECLARE
   rec   record;
   nbrow bigint;
BEGIN
   FOR rec IN
      SELECT *
      FROM   pg_tables
      WHERE  tablename NOT LIKE 'pg\_%'
      ORDER  BY tablename
   LOOP
      EXECUTE 'SELECT count(*) FROM '
        || quote_ident(rec.schemaname) || '.'
        || quote_ident(rec.tablename)
      INTO nbrow;
      -- Do something with nbrow
   END LOOP;
END
$$;

Vous devez inclure le nom du schéma pour que cela fonctionne pour tous les schémas (y compris ceux qui ne figurent pas dans votre search_path ).

De plus, vous avez en fait besoin utiliser quote_ident() ou format() avec %I ou une regclass variable pour se prémunir contre l'injection SQL. Un nom de table peut être presque n'importe quoi entre guillemets doubles. Voir :

  • Nom de table en tant que paramètre de fonction PostgreSQL

Petit détail :échapper le trait de soulignement (_ ) dans le LIKE modèle pour en faire un littéral trait de soulignement :tablename NOT LIKE 'pg\_%'

Comment puis-je procéder :

DO
$$
DECLARE
    tbl   regclass;
    nbrow bigint;
BEGIN
   FOR tbl IN
      SELECT c.oid
      FROM   pg_class     c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  c.relkind = 'r'
      AND    n.nspname NOT LIKE 'pg\_%'         -- system schema(s)
      AND    n.nspname <> 'information_schema'  -- information schema
      ORDER  BY n.nspname, c.relname
   LOOP
      EXECUTE 'SELECT count(*) FROM ' || tbl INTO nbrow;
      -- raise notice '%: % rows', tbl, nbrow;
   END LOOP;
END
$$;

Requête pg_catalog.pg_class au lieu de tablename , il fournit l'OID de la table.

Le type d'identifiant d'objet regclass est pratique pour simplifier. En particulier, les noms de table sont entre guillemets doubles et qualifiés de schéma si nécessaire automatiquement (empêche également l'injection SQL).

Cette requête exclut également les tables temporaires (le schéma temporaire est nommé pg_temp% en interne).

Pour n'inclure que les tables d'un schéma donné :

    AND    n.nspname = 'public' -- schema name here, case-sensitive