web-dev-qa-db-fra.com

Comment puis-je supprimer toutes les tables d'une base de données PostgreSQL?

Comment puis-je supprimer toutes les tables dans PostgreSQL, à partir de la ligne de commande?

Je ne veux pas vouloir supprimer la base de données elle-même, mais uniquement toutes les tables et toutes les données qu'elles contiennent.

796
AP257

Si toutes vos tables sont dans un seul schéma, cette approche pourrait fonctionner (le code ci-dessous suppose que le nom de votre schéma est public)

DROP SCHEMA public CASCADE;
CREATE SCHEMA public;

Si vous utilisez PostgreSQL 9.3 ou une version supérieure, vous devrez peut-être également restaurer les droits par défaut.

GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
1134
Derek Slife

Vous pouvez écrire une requête pour générer un script SQL comme ceci:

select 'drop table "' || tablename || '" cascade;' from pg_tables;

Ou:

select 'drop table if exists "' || tablename || '" cascade;' from pg_tables;

Dans le cas où certaines tables sont automatiquement supprimées en raison de l'option de cascade dans une phrase précédente.

En outre, comme indiqué dans les commentaires, vous pouvez filtrer les tables que vous souhaitez supprimer par nom de schéma:

select 'drop table if exists "' || tablename || '" cascade;' 
  from pg_tables
 where schemaname = 'public'; -- or any other schema

Et puis lancez-le.

Glorious COPY + PASTE fonctionnera également.

321
Pablo Santa Cruz

La réponse la plus acceptée au moment de la rédaction de cet article (janvier 2014) est:

drop schema public cascade;
create schema public;

Cela fonctionne. Toutefois, si votre intention est de restaurer le schéma public à son état vierge, la tâche n’est pas entièrement accomplie. Sous pgAdmin III pour PostgreSQL 9.3.1, si vous cliquez sur le schéma "public" ainsi créé et regardez dans le "volet SQL", vous verrez ce qui suit:

-- Schema: public

-- DROP SCHEMA public;

CREATE SCHEMA public
  AUTHORIZATION postgres;

En revanche, une toute nouvelle base de données comportera les éléments suivants:

-- Schema: public

-- DROP SCHEMA public;

CREATE SCHEMA public
  AUTHORIZATION postgres;

GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public
  IS 'standard public schema';

Pour moi, utiliser un framework web python qui crée des tables de base de données (web2py), en utilisant l’ancien, posait des problèmes:

<class 'psycopg2.ProgrammingError'> no schema has been selected to create in 

Donc, à mon avis, la réponse tout à fait correcte est:

DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public IS 'standard public schema';

(note également pour émettre ces commandes depuis pgAdmin III, je suis allé dans Plugins-> Console PSQL)

226
User

Vous pouvez supprimer toutes les tables avec

DO $$ DECLARE
    r RECORD;
BEGIN
    -- if the schema you operate on is not "current", you will want to
    -- replace current_schema() in query with 'schematodeletetablesfrom'
    -- *and* update the generate 'DROP...' accordingly.
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
        EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
    END LOOP;
END $$;

IMO, cela vaut mieux que drop schema public, car vous n'avez pas besoin de recréer la schema et de restaurer toutes les autorisations. 

De plus, cela ne nécessite pas de langage de script externe, ni de copier-coller du code SQL généré sur l'interprète.

107
Piotr Findeisen

Si tout ce que vous voulez supprimer appartient au même utilisateur, vous pouvez utiliser: 

drop owned by the_user;

Cela supprimera tout que l’utilisateur possède. 

Cela inclut les vues matérialisées, vues, séquences, déclencheurs, schémas, fonctions, types, agrégats, opérateurs, domaines, etc. (donc, vraiment: tout) que the_user possède (= créé). 

Vous devez remplacer the_user par le nom d'utilisateur actuel, il n'existe actuellement aucune option pour tout supprimer pour "l'utilisateur actuel". La prochaine version 9.5 aura l'option drop owned by current_user.

Plus de détails dans le manuel: http://www.postgresql.org/docs/current/static/sql-drop-owned.html

78

Selon Pablo ci-dessus, il suffit de quitter un schéma spécifique, en ce qui concerne le cas: 

select 'drop table "' || tablename || '" cascade;' 
from pg_tables where schemaname = 'public';
64
LenW
drop schema public cascade;

devrait faire l'affaire. 

39
Joe Van Dyk

Après Pablo et LenW, voici un one-liner qui prépare tout et exécute ensuite: 

psql -U $PGUSER $PGDB -t -c "select 'drop table \"' || tablename || '\" cascade;' from pg_tables where schemaname = 'public'" | psql -U $PGUSER $PGDB

NB: soit définir, soit remplacer $PGUSER et $PGDB par les valeurs souhaitées  

27
Tim Diggins

Si vous avez le langage procédural PL/PGSQL installé vous pouvez utiliser ce qui suit pour tout supprimer sans script externe Shell/Perl.

DROP FUNCTION IF EXISTS remove_all();

CREATE FUNCTION remove_all() RETURNS void AS $$
DECLARE
    rec RECORD;
    cmd text;
BEGIN
    cmd := '';

    FOR rec IN SELECT
            'DROP SEQUENCE ' || quote_ident(n.nspname) || '.'
                || quote_ident(c.relname) || ' CASCADE;' AS name
        FROM
            pg_catalog.pg_class AS c
        LEFT JOIN
            pg_catalog.pg_namespace AS n
        ON
            n.oid = c.relnamespace
        WHERE
            relkind = 'S' AND
            n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
            pg_catalog.pg_table_is_visible(c.oid)
    LOOP
        cmd := cmd || rec.name;
    END LOOP;

    FOR rec IN SELECT
            'DROP TABLE ' || quote_ident(n.nspname) || '.'
                || quote_ident(c.relname) || ' CASCADE;' AS name
        FROM
            pg_catalog.pg_class AS c
        LEFT JOIN
            pg_catalog.pg_namespace AS n
        ON
            n.oid = c.relnamespace WHERE relkind = 'r' AND
            n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
            pg_catalog.pg_table_is_visible(c.oid)
    LOOP
        cmd := cmd || rec.name;
    END LOOP;

    FOR rec IN SELECT
            'DROP FUNCTION ' || quote_ident(ns.nspname) || '.'
                || quote_ident(proname) || '(' || oidvectortypes(proargtypes)
                || ');' AS name
        FROM
            pg_proc
        INNER JOIN
            pg_namespace ns
        ON
            (pg_proc.pronamespace = ns.oid)
        WHERE
            ns.nspname =
            'public'
        ORDER BY
            proname
    LOOP
        cmd := cmd || rec.name;
    END LOOP;

    EXECUTE cmd;
    RETURN;
END;
$$ LANGUAGE plpgsql;

SELECT remove_all();

Plutôt que de taper ceci à l'invite "psql", je vous suggère de le copier dans un fichier, puis de le transmettre en entrée dans psql à l'aide des options "--file" ou "-f":

psql -f clean_all_pg.sql

Crédit lorsque le crédit est dû: j’ai écrit la fonction, mais je pense que les requêtes (ou la première du moins) ont été envoyées par une personne figurant sur une des listes de diffusion de pgsql il ya des années. Je ne me souviens pas exactement quand ni lequel.

20
Mark Lawrence

J'ai légèrement modifié la réponse de Pablo pour la commodité de renvoyer les commandes SQL générées sous forme d'une seule chaîne:

select string_agg('drop table "' || tablename || '" cascade', '; ') 
from pg_tables where schemaname = 'public'
11
Adé

Utilisez ce script dans pgAdmin:

DO $$
DECLARE 
    brow record;
BEGIN
    FOR brow IN (select 'drop table "' || tablename || '" cascade;' as table_name from pg_tables where schemaname = 'public') LOOP
        EXECUTE brow.table_name;
    END LOOP;
END; $$
9
Luca Perico

Juste au cas où ... Un script simple Python qui nettoie la base de données Postgresql

import psycopg2
import sys

# Drop all tables from a given database

try:
    conn = psycopg2.connect("dbname='akcja_miasto' user='postgres' password='postgres'")
    conn.set_isolation_level(0)
except:
    print "Unable to connect to the database."

cur = conn.cursor()

try:
    cur.execute("SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name")
    rows = cur.fetchall()
    for row in rows:
        print "dropping table: ", row[1]   
        cur.execute("drop table " + row[1] + " cascade") 
    cur.close()
    conn.close()        
except:
    print "Error: ", sys.exc_info()[1]

Assurez-vous qu’après la copie, l’indentation est correcte car Python s’appuie dessus.

8
Piotr Kochański

Vous pouvez utiliser la fonction string_agg pour créer une liste séparée par des virgules, idéale pour DROP TABLE . À partir d'un script bash:

#!/bin/bash
TABLES=`psql $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public'"`

echo Dropping tables:${TABLES}
psql $PGDB --command "DROP TABLE IF EXISTS ${TABLES} CASCADE"
6
Jamie

Vous devez supprimer des tableaux et des séquences, voici ce qui a fonctionné pour moi

psql -qAtX -c "select 'DROP TABLE IF EXISTS ' || quote_ident(table_schema) || '.' || quote_ident(table_name) || ' CASCADE;' FROM information_schema.tables where table_type = 'BASE TABLE' and not table_schema ~ '^(information_schema|pg_.*)$'" | psql -qAtX
psql -qAtX -c "select 'DROP SEQUENCE IF EXISTS ' || quote_ident(relname) || ' CASCADE;' from pg_statio_user_sequences;" | psql -qAtX

avant d'exécuter la commande, vous devrez peut-être utiliser Sudo/su pour l'utilisateur postgres ou (informations de connexion d'exportation PGHOST, PGPORT, PGUSER et PGPASSWORD), puis export PGDATABASE=yourdatabase 

4
Muayyad Alsadi

Si vous souhaitez supprimer des données (pas supprimer un tableau):

-- Truncate tables and restart sequnces
SELECT 'TRUNCATE TABLE "' || table_schema || '"."' || table_name || '" RESTART IDENTITY CASCADE;' 
FROM information_schema.tables 
WHERE table_catalog = '<database>' AND table_schema = '<schema>';

Ou si vous voulez une table basse, vous pouvez utiliser ce sql:

-- For tables
SELECT 'DROP TABLE "' || table_schema || '"."' || table_name || '" CASCADE;' 
FROM information_schema.tables 
WHERE table_catalog = '<database>' AND table_schema = '<schema>';

-- For sequences
SELECT 'DROP SEQUENCE d_a_seq "' || sequence_schema || '"."' || sequence_name || '";' 
FROM information_schema.sequences 
WHERE sequence_catalog = '<database>' AND sequence_schema = '<schema>';
3
pooya

Tâche rake pour Rails pour détruire toutes les tables de la base de données courante

namespace :db do
  # rake db:drop_all_tables
  task drop_all_tables: :environment do
    query = <<-QUERY
      SELECT
        table_name
      FROM
        information_schema.tables
      WHERE
        table_type = 'BASE TABLE'
      AND
        table_schema NOT IN ('pg_catalog', 'information_schema');
    QUERY

    connection = ActiveRecord::Base.connection
    results    = connection.execute query

    tables = results.map do |line|
      table_name = line['table_name']
    end.join ", "

    connection.execute "DROP TABLE IF EXISTS #{ tables } CASCADE;"
  end
end
3
the-teacher

dans un fichier batch Windows:

@echo off
FOR /f "tokens=2 delims=|" %%G IN ('psql --Host localhost --username postgres --command="\dt" YOUR_TABLE_NAME') DO (
   psql --Host localhost --username postgres --command="DROP table if exists %%G cascade" sfkb
   echo table %%G dropped
)
2
Lewis

J'ai amélioré la méthode bash de jamie en prenant en charge les vues car il ne respecte que le type de table "table de base" qui est la valeur par défaut.

le code bash suivant supprime les vues en premier, puis tout le reste

#!/usr/bin/env bash

PGDB="yourDB"
# By exporting user & pass your dont need to interactively type them on execution
export PGUSER="PGusername"
export PGPASSWORD="PGpassword"

VIEWS=`psql -d $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public' AND table_type='VIEW'"`
BASETBLS=`psql -d $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE'"`

echo Dropping views:${VIEWS}
psql $PGDB --command "DROP VIEW IF EXISTS ${VIEWS} CASCADE"
echo Dropping tables:${BASETBLS}
psql $PGDB --command "DROP TABLE IF EXISTS ${BASETBLS} CASCADE"
2
martinseener

et bien, j'aime travailler depuis la ligne de commande ...

psql -U <user> -d <mydb> -c '\dt' | cut -d ' ' -f 4 | sed -e "s/^/drop table if exists /" | sed -e "s/$/;/"

-c '\dt' invoquera la commande list tables.

List of relations Schema | Name | Type | Owner --------+-------------------+-------+---------- public | _d_psidxddlparm | table | djuser public | _d_psindexdefn | table | djuser

cut -d ' ' -f 4 maintenant, dirigez sa sortie pour récupérer le 4ème champ (lorsque vous utilisez l'espace comme séparateur), qui est la table.

sed est ensuite utilisé pour préfixer un drop table et pour suffixer le séparateur de commande ;

| egrep '_d_' - Ajoutez-y un peu plus de grep et vous pourrez être plus sélectif quant aux tables que vous supprimez.

drop table if exists _d_psidxddlparm; drop table if exists _d_psindexdefn;

Remarque: tel que rédigé, cela générera des lignes erronées pour la sortie des commandes \dt des en-têtes de colonne et le nombre total de lignes à la fin. J'évite cela en faisant un grepping, mais vous pouvez utiliser head et tail.

0
JL Peyret

De toute façon, si vous voulez utiliser toutes les tables, vous pouvez vous passer de subtilités telles que CASCADE en les mettant toutes dans une seule instruction. Cela rend également l'exécution plus rapide.

SELECT 'TRUNCATE TABLE ' || string_agg('"' || tablename || '"', ', ') || ';' 
FROM pg_tables WHERE schemaname = 'public';

L'exécuter directement:

DO $$
DECLARE tablenames text;
BEGIN    
    tablenames := string_agg('"' || tablename || '"', ', ') 
        FROM pg_tables WHERE schemaname = 'public';
    EXECUTE 'TRUNCATE TABLE ' || tablenames;
END; $$

Remplacez TRUNCATE par DROP selon le cas.

0
Endre Both

Le moyen le plus simple consiste à supprimer le schéma public, comme d'autres l'ont suggéré dans des réponses précédentes. Cependant, ce n'est pas un bon moyen. Vous ne savez jamais ce qui a été fait au schéma public qui a été oublié depuis et qui n'a pas été documenté. Vous ne savez pas non plus si cela fonctionnera de la même manière dans le futur. Dans la V9, cela aurait été correct, mais dans la V10, tous vos utilisateurs perdraient l'accès au schéma et devaient se voir accorder un autre accès, sans quoi votre application serait interrompue. Je n'ai pas vérifié la V11, mais le fait est que vous ne savez jamais ce qui va casser si vous passez d'une machine à une autre, d'un site à l'autre ou d'une version à l'autre. Cela est également impossible si vous êtes un utilisateur ayant accès à la base de données, mais pas au schéma.

Si vous avez besoin de le faire par programme, les autres réponses ci-dessus le couvrent, mais l'une des choses que les réponses ci-dessus ne prennent pas en compte est de demander à Postgres de faire le travail pour vous. Si vous utilisez pg_dump avec l'option -c comme ci-dessous:

Sudo su postgres -c "pg_dump -U postgres WhateverDB -c -f "/home/Anyone/DBBackupWhateverDB-ServerUnscheduled.sql""

Cela créera un script de restauration de base de données avec des instructions SQL supprimant toutes les tables.

Si le seul but de la question était de supprimer les tables avant la restauration, votre restauration fera le travail à votre place.

Toutefois, si vous en avez besoin pour autre chose, vous pouvez simplement copier les instructions de suppression à partir du script SQL.

0
RichardP

Pour les cas où vous ne pouvez pas simplement utiliser DROP SCHEMA public CASCADE;, DROP OWNED BY current_user; ou quelque chose du genre, voici un script SQL autonome que j'ai écrit et qui est sécurisé pour les transactions (vous pouvez le placer entre BEGIN; et ROLLBACK; pour le tester ou COMMIT; pour réellement faire l'acte) et nettoie «tous» les objets de base de données… eh bien, tous ceux utilisés dans la base de données que notre application utilise ou que je pourrais ajouter judicieusement, qui est:

  • déclencheurs sur les tables
  • contraintes sur les tables (FK, PK, CHECK, UNIQUE)
  • indices
  • VIEWs (normal ou matérialisé)
  • les tables
  • des séquences
  • fonctions/procédures ( pg_proc.proisagg probablement devrait être respecté quoique)
  • tous les schémas nōn-default (c'est-à-dire non public ou internes à la base de données) «nous» possédons: le script est utile lorsqu'il est exécuté comme «non superutilisateur de base de données»; un superutilisateur peut supprimer tous les schémas (les plus importants restent explicitement exclus, cependant)

Ne sont pas laissés tomber (certains délibérés; d'autres uniquement parce que je n'avais aucun exemple dans notre DB):

  • le schéma public (par exemple pour les éléments fournis par leur extension)
  • des extensions
  • fonctions agrégées
  • des collations et autres objets locaux
  • déclencheurs d'événements
  • recherche de texte,… (voir ici pour d'autres choses que j'ai peut-être manquées)
  • rôles ou autres paramètres de sécurité
  • types composites
  • tables de pain grillé
  • FDW et tables étrangères

J'ai aussi une version qui supprime «tout sauf deux tables et ce qui leur appartient» au cas où quelqu'un serait intéressé; le diff est petit. Contactez moi si nécessaire.

SQL

-- Copyright © 2019
--      mirabilos <[email protected]>
--
-- Provided that these terms and disclaimer and all copyright notices
-- are retained or reproduced in an accompanying document, permission
-- is granted to deal in this work without restriction, including un‐
-- limited rights to use, publicly perform, distribute, sell, modify,
-- merge, give away, or sublicence.
--
-- This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
-- the utmost extent permitted by applicable law, neither express nor
-- implied; without malicious intent or gross negligence. In no event
-- may a licensor, author or contributor be held liable for indirect,
-- direct, other damage, loss, or other issues arising in any way out
-- of dealing in the work, even if advised of the possibility of such
-- damage or existence of a defect, except proven that it results out
-- of said person’s immediate fault when using the work as intended.
-- -
-- Drop everything from the PostgreSQL database.

DO $$
DECLARE
        r RECORD;
BEGIN
        -- triggers
        FOR r IN (SELECT pns.nspname, pc.relname, pt.tgname
                FROM pg_trigger pt, pg_class pc, pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pt.tgrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pt.tgisinternal=false
            ) LOOP
                EXECUTE format('DROP TRIGGER %I ON %I.%I;',
                    r.tgname, r.nspname, r.relname);
        END LOOP;
        -- constraints #1: foreign key
        FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
                FROM pg_constraint pcon, pg_class pc, pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pcon.contype='f'
            ) LOOP
                EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
                    r.nspname, r.relname, r.conname);
        END LOOP;
        -- constraints #2: the rest
        FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
                FROM pg_constraint pcon, pg_class pc, pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pcon.contype<>'f'
            ) LOOP
                EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
                    r.nspname, r.relname, r.conname);
        END LOOP;
        -- indicēs
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_class pc, pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='i'
            ) LOOP
                EXECUTE format('DROP INDEX %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- normal and materialised views
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_class pc, pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind IN ('v', 'm')
            ) LOOP
                EXECUTE format('DROP VIEW %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- tables
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_class pc, pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='r'
            ) LOOP
                EXECUTE format('DROP TABLE %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- sequences
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_class pc, pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='S'
            ) LOOP
                EXECUTE format('DROP SEQUENCE %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- functions / procedures
        FOR r IN (SELECT pns.nspname, pp.proname, pp.oid
                FROM pg_proc pp, pg_namespace pns
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
            ) LOOP
                EXECUTE format('DROP FUNCTION %I.%I(%s);',
                    r.nspname, r.proname,
                    pg_get_function_identity_arguments(r.oid));
        END LOOP;
        -- nōn-default schemata we own; assume to be run by a not-superuser
        FOR r IN (SELECT pns.nspname
                FROM pg_namespace pns, pg_roles pr
                WHERE pr.oid=pns.nspowner
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast', 'public')
                    AND pr.rolname=current_user
            ) LOOP
                EXECUTE format('DROP SCHEMA %I;', r.nspname);
        END LOOP;
        -- voilà
        RAISE NOTICE 'Database cleared!';
END; $$;

Testé sur PostgreSQL 9.6 (jessie-backports). Les corrections de bugs et autres améliorations sont les bienvenues!

0
mirabilos