175 votes

Tronquer toutes les tables d'une base de données Postgres

J'ai régulièrement besoin de supprimer toutes les données de ma base de données PostgreSQL avant une reconstruction. Comment puis-je le faire directement en SQL ?

Pour l'instant, j'ai réussi à trouver une instruction SQL qui renvoie toutes les commandes que je dois exécuter :

SELECT 'TRUNCATE TABLE ' ||  tablename || ';' FROM pg_tables WHERE tableowner='MYUSER';

Mais je ne vois pas comment les exécuter par programme une fois que je les ai.

258voto

Henning Points 3211

FrustratedWithFormsDesigner a raison, PL/pgSQL peut le faire. Voici le script :

CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$
DECLARE
    statements CURSOR FOR
        SELECT tablename FROM pg_tables
        WHERE tableowner = username AND schemaname = 'public';
BEGIN
    FOR stmt IN statements LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Cela crée une fonction stockée (vous ne devez le faire qu'une seule fois) que vous pouvez ensuite utiliser comme ceci :

SELECT truncate_tables('MYUSER');

1 votes

J'ai dû modifier un peu le système, mais après ça, ça a marché comme sur des roulettes ! Je n'ai jamais utilisé plpgsql avant, donc cela m'aurait pris des siècles. Merci ! Pour ceux qui en ont besoin, j'ai ajouté le code que j'ai fini par utiliser en bas de ce post.

0 votes

Désolé, je pensais probablement en Oracle PL/SQL :( J'ai corrigé l'erreur de syntaxe dans mon code ci-dessus.

2 votes

Vous pouvez également déplacer l'instruction SELECT directement dans la boucle FOR. DECLARE r RECORD; puis pour la boucle : FOR r IN SELECT tablename FROM pg_tables LOOP

103voto

Erwin Brandstetter Points 110228

Les curseurs explicites sont rarement nécessaires en plpgsql. Utilisez la méthode plus simple et plus rapide curseur implicite d'un FOR boucle :

Nota: Comme les noms de table ne sont pas uniques par base de données, vous devez qualifier les noms de table en fonction du schéma pour être sûr. En outre, je limite la fonction au schéma par défaut "public". Adaptez-la à vos besoins, mais veillez à exclure les schémas du système. pg_* y information_schema .

Soyez très prudent avec ces fonctions. Ils détruisent votre base de données. J'ai ajouté une sécurité enfant. Commente le RAISE NOTICE 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  
      -- dangerous, test before you execute!
      RAISE NOTICE '%',  -- once confident, comment this line ...
      -- EXECUTE         -- ... and uncomment this one
         format('TRUNCATE TABLE %I.%I CASCADE', _sch, _tbl);
   END LOOP;
END
$func$ LANGUAGE plpgsql;

format() nécessite Postgres 9.1 ou une version ultérieure. Dans les versions plus anciennes, concaténer 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 besoin de curseur ou de boucle :

Agrégez 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
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
  (SELECT 'TRUNCATE TABLE '
       || string_agg(format('%I.%I', schemaname, tablename), ', ')
       || ' CASCADE'
   FROM   pg_tables
   WHERE  tableowner = _username
   AND    schemaname = 'public'
   );
END
$func$ LANGUAGE plpgsql;

Appelez :

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 fonction DO déclaration. Et dans Postgres 9.5+, la syntaxe peut être encore plus simple :

DO
$func$
BEGIN
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
   (SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
    FROM   pg_class
    WHERE  relkind = 'r'  -- only tables
    AND    relnamespace = 'public'::regnamespace
   );
END
$func$;

A propos de la différence entre pg_class , pg_tables y information_schema.tables :

À propos de regclass et les noms de table cités :

Pour un usage répété

Crear un Base de données "modèle". (appelons-la my_template ) avec votre structure vanille et toutes les tables vides. Puis passez par un DROP / CREATE DATABASE cycle :

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

C'est extrêmement rapide car Postgres copie l'ensemble de la structure au niveau du fichier. Il n'y a pas de problèmes de concurrence ou d'autres frais généraux qui vous ralentissent.

Si les connexions simultanées vous empêchent d'abandonner le DB, envisagez de le faire :

1 votes

Il est intéressant de noter que cette dernière fonction a effacé TOUTES les bases de données. Pas seulement celle qui est actuellement connectée, one.... ouais... appelez-moi naïf mais ce n'était vraiment pas clair dans ce post.

0 votes

@Amalgovinus : Quelle dernière fonction ? Aucune des fonctions de ma réponse ne touche quoi que ce soit en dehors de la fonction actuel (sauf pour DROP DATABASE mydb évidemment). Est-ce que vous confondez schémas avec des bases de données, peut-être ?

0 votes

Le tout dernier avec DO $func$. J'ai utilisé le même nom de schéma dans deux bases de données différentes, donc il semble que mes données ont été supprimées des deux. Donc oui, j'ai confondu ces deux-là

42voto

Sandip Ransing Points 2344

Si je dois le faire, je vais simplement créer un schéma sql de la base de données actuelle, puis abandonner et créer la base de données, puis charger la base de données avec le schéma sql.

Voici les étapes à suivre :

1) Créer un dump de schéma de la base de données ( --schema-only )

pg_dump mydb -s > schema.sql

2) Abandon de la base de données

drop database mydb;

3) Créer une base de données

create database mydb;

4) Importer le schéma

psql mydb < schema.sql

10voto

Scott Bailey Points 2094

Dans ce cas, il serait probablement préférable de disposer d'une base de données vide que vous utilisez comme modèle et, lorsque vous avez besoin d'une actualisation, de supprimer la base de données existante et d'en créer une nouvelle à partir du modèle.

3voto

Aaron Points 1903

Légèrement adapté...

CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$
DECLARE
    stmt RECORD;
    statements CURSOR FOR SELECT tablename FROM pg_tables WHERE tableowner = username;
BEGIN
    FOR stmt IN statements LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';
    END LOOP;
END;                         
$$ LANGUAGE 'plpgsql';

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X