Les curseurs explicites sont rarement nécessaires dans plpgsql. Utilisez le curseur implicite plus simple et plus rapide d'une FOR
boucle:
Remarque: étant donné que les noms de table ne sont pas uniques par base de données, vous devez les qualifier de schéma pour être sûr. De plus, je limite la fonction au schéma par défaut «public». Adaptez-vous à vos besoins, mais veillez à exclure les schémas système pg_*
et information_schema
.
Soyez très prudent avec ces fonctions. Ils détruisent votre base de données. J'ai ajouté un dispositif de sécurité pour enfants. Commentez la RAISE NOTICE
ligne et décommentez EXECUTE
pour amorcer la bombe ...
CREATE OR REPLACE FUNCTION f_truncate_tables(_username text)
RETURNS void AS
$func$
DECLARE
_tbl text;
_sch text;
BEGIN
FOR _sch, _tbl IN
SELECT schemaname, tablename
FROM pg_tables
WHERE tableowner = _username
AND schemaname = 'public'
LOOP
RAISE NOTICE '%',
-- EXECUTE -- dangerous, test before you execute!
format('TRUNCATE TABLE %I.%I CASCADE', _sch, _tbl);
END LOOP;
END
$func$ LANGUAGE plpgsql;
format()
nécessite Postgres 9.1 ou version ultérieure. Dans les anciennes versions, concaténez la chaîne de requête comme ceci:
'TRUNCATE TABLE ' || quote_ident(_sch) || '.' || quote_ident(_tbl) || ' CASCADE';
Commande unique, pas de boucle
Puisque nous pouvons TRUNCATE
plusieurs tables à la fois, nous n'avons pas du tout besoin de curseur ou de boucle:
Regroupez tous les noms de table et exécutez une seule instruction. Plus simple, plus rapide:
CREATE OR REPLACE FUNCTION f_truncate_tables(_username text)
RETURNS void AS
$func$
BEGIN
RAISE NOTICE '%',
-- EXECUTE -- dangerous, test before you execute!
(SELECT 'TRUNCATE TABLE '
|| string_agg(format('%I.%I', schemaname, tablename), ', ')
|| ' CASCADE'
FROM pg_tables
WHERE tableowner = _username
AND schemaname = 'public'
);
END
$func$ LANGUAGE plpgsql;
Appel:
SELECT truncate_tables('postgres');
Requête affinée
Vous n'avez même pas besoin d'une fonction. Dans Postgres 9.0+, vous pouvez exécuter des commandes dynamiques dans une DO
instruction. Et dans Postgres 9.5+, la syntaxe peut être encore plus simple:
DO
$func$
BEGIN
RAISE NOTICE '%',
-- EXECUTE
(SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
FROM pg_class
WHERE relkind = 'r' -- only tables
AND relnamespace = 'public'::regnamespace
);
END
$func$;
À propos de la différence entre pg_class
, pg_tables
et information_schema.tables
:
À propos regclass
et noms de table cités:
Pour usage répété
Créez une base de données "modèle" (nommons-la my_template
) avec votre structure vanille et toutes les tables vides. Puis passez par un cycle DROP
/CREATE DATABASE
:
DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;
C'est extrêmement rapide , car Postgres copie toute la structure au niveau du fichier. Aucun problème de concurrence ou autre surcharge ne vous ralentit.
Si les connexions simultanées vous empêchent de supprimer la base de données, envisagez: