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