Elimina tutti i dati nel database Postgres


14

Ho creato un nuovo dump db da un server di produzione con i flag --data-onlye --column-inserts, quindi ho solo un mucchio di istruzioni insert per inserire dati quando eseguo un ripristino su un server di gestione temporanea.

pg_dump -h localhost -U adminuser --data-only --column-inserts maindb > maindb.sql

Come si eliminano prima tutti i dati nel database del server di gestione temporanea, prima di ripristinare i dati dal dump della produzione?

Voglio eliminare solo tutti i dati, quindi non devo rilasciare e creare il database e tutto il resto. Voglio solo rimuovere i dati e inserire nuovi dati.

Non ho la possibilità di rilasciare e creare il database per diversi motivi. Dovrò rimuovere tutti i dati e inserirli solo, quindi tutto ciò che serve per trovare come farlo, sono disposto a cercarlo, ma ovviamente ho bisogno di aiuto per iniziare.

Devo anche automatizzare questo processo. Automatizzerà "il dumping dei dati dal db di produzione", quindi "l'eliminazione dei dati dal db di gestione temporanea" e quindi "il ripristino dei dati dal db di gestione temporanea". Ho solo bisogno di aiuto per la parte "eliminazione dei dati sulla gestione temporanea db".

Sono in esecuzione su PostgreSQL 9.5.2

Risposte:


24

Non è necessario eliminare il database, dovrebbe essere sufficiente eliminare tutti gli oggetti nel database. Questo può essere fatto usando

drop owned by adminuser

Se poi crei il dump SQL includendo le create tableistruzioni (quindi senza l' --data-onlyopzione) tutto dovrebbe andare bene.

Puoi anche rimuovere --column-insertsquindi, il che renderà l'importazione molto più veloce.


Tuttavia, se si desidera eliminare tutto, è possibile farlo con un piccolo SQL dinamico:

do
$$
declare
  l_stmt text;
begin
  select 'truncate ' || string_agg(format('%I.%I', schemaname, tablename), ',')
    into l_stmt
  from pg_tables
  where schemaname in ('public');

  execute l_stmt;
end;
$$

Questo troncerà tutte le tabelle nello schema publiccon una singola istruzione che funzionerà anche se ci sono molti vincoli di chiave esterna che collegano tutte le tabelle. Se le tabelle sono distribuite su più schemi, è necessario aggiungerle nella wherecondizione.


vedo ... fa lo stesso di @ypercube sopra menzionato per usare questo comando TRUNCATE table1, table2, ... <list of all tables>;? fanno entrambi la stessa cosa?
Uberrebu,

1
@babababa: sì, la mia risposta semplicemente genera ed esegue questa istruzione in modo dinamico, quindi non è necessario digitare tutti i nomi delle tabelle e se aggiungi una nuova tabella verrà automaticamente inclusa.
a_horse_with_no_name

bello appena provato e funziona, @ypercube funziona anche uno ... grazie mille
uberrebu

6

pg_restore ha un flag --clean (o eventualmente --create) che cancellerà automaticamente i dati prima di eseguire le operazioni.

L'eccellente documentazione dovrebbe aiutarti molto ...

Giusto per chiarire, nel caso in cui sia confuso:

Pulire (rilasciare) gli oggetti del database prima di ricrearli. (Se non viene utilizzato --if-esiste, questo potrebbe generare alcuni messaggi di errore innocui, se non fossero presenti oggetti nel database di destinazione.)

Questo non lascerà cadere il database reale .. solo le tabelle / viste / ecc.

Se, per qualche motivo, eliminare e ricreare le tabelle non è accettabile, dovrai impegnarti di più per creare manualmente uno script che crei un data onlydump dal database di origine, problemi TRUNCATEo DELETEnel database di destinazione, quindi carica il dump dei dati. Per quanto ne so, non esiste un modo rapido / fluido per farlo.


quel flag --clean eliminerà SOLO i dati e manterrà le strutture di database e tabelle uguali ma vuote?
Uberrebu,

Emetterà una tabella di rilascio prima di una tabella di creazione. Qualsiasi tabella esistente nel file di dump. Spero che il file di dump contenga le informazioni per ricreare la tabella esattamente come esisteva prima (inclusi FKeys, ecc.). Ma dipende davvero da come è stato creato il file di dump. Tuttavia, poiché continui a menzionare la "gestione temporanea", sembra che ciò che stai veramente cercando sia un modo per popolare le tabelle di gestione temporanea in un data warehouse con i dati di un db di produzione. Se questo è il tuo obiettivo, un file di dump è probabilmente l'approccio sbagliato ..
Joishi Bodio

non è quello che sto cercando di fare, voglio solo cancellare i dati ... la struttura del database e delle tabelle rimarrà invariata e intatta ... la mia domanda è abbastanza chiara su cosa voglio fare, anche dal titolo
uberrebu

Quindi, mi spiace dirlo, la tua soluzione sarà molto più difficile.
Joishi Bodio,

3
SELECT 'TRUNCATE ' || input_table_name || ' CASCADE;' AS truncate_query FROM(SELECT table_schema || '.' || table_name AS input_table_name FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema') AND table_schema NOT LIKE 'pg_toast%') AS information;  

La query sopra genererà query troncate per tutte le tabelle nel database.


0

Nota: la mia risposta riguarda davvero l'eliminazione delle tabelle e di altri oggetti del database; per eliminare tutti i dati nelle tabelle, ovvero troncare tutte le tabelle , Endre Both ha fornito un'istruzione altrettanto ben eseguita (esecuzione diretta) un mese dopo.

Per i casi in cui non puoi semplicemente DROP SCHEMA public CASCADE;, DROP OWNED BY current_user;o qualcosa del genere, ecco uno script SQL autonomo che ho scritto, che è sicuro per le transazioni (cioè puoi metterlo tra BEGIN;e o ROLLBACK;semplicemente testarlo o COMMIT;fare effettivamente l'atto) e pulisce "tutti" gli oggetti del database ... beh, tutti quelli utilizzati nel database che la nostra applicazione utilizza o che potrei aggiungere sensatamente, che è:

  • si innesca sui tavoli
  • vincoli sulle tabelle (FK, PK, CHECK, UNIQUE)
  • Indici
  • VIEWs (normale o materializzato)
  • tavoli
  • sequenze
  • routine (funzioni aggregate, funzioni, procedure)
  • tutti gli schemi nōn-default (cioè no publico DB-internal) "noi" possediamo: lo script è utile quando eseguito come "non un superutente del database"; un superutente può eliminare tutti gli schemi (quelli veramente importanti sono comunque esplicitamente esclusi)
  • estensioni (fornite dall'utente ma normalmente le lascio deliberatamente)

Non vengono rilasciati (alcuni deliberati; alcuni solo perché non avevo un esempio nel nostro DB):

  • lo publicschema (ad es. per contenuti forniti dall'estensione in essi)
  • collazioni e altre cose locali
  • trigger di eventi
  • ricerca di testo, ... (vedi qui per altre cose che potrei aver perso)
  • ruoli o altre impostazioni di sicurezza
  • tipi compositi
  • tavoli toast
  • FDW e tavoli stranieri

Ciò è molto utile nei casi in cui il dump che si desidera ripristinare abbia una versione dello schema del database diversa (ad es. Con Debian dbconfig-common, Flyway o Liquibase / DB-Manul) rispetto al database in cui si desidera ripristinarlo.

Ho anche una versione che elimina "tutto tranne due tabelle e ciò che appartiene a loro" (una sequenza, testata manualmente, scusate, lo so, noioso) nel caso qualcuno fosse interessato; il diff è piccolo. Contattatemi o controllate questo repository se interessati.

SQL

-- Copyright © 2019, 2020
--      mirabilos <t.glaser@tarent.de>
--
-- 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
        q TEXT;
        r RECORD;
BEGIN
        -- triggers
        FOR r IN (SELECT pns.nspname, pc.relname, pt.tgname
                FROM pg_catalog.pg_trigger pt, pg_catalog.pg_class pc, pg_catalog.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_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.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_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.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_catalog.pg_class pc, pg_catalog.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_catalog.pg_class pc, pg_catalog.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_catalog.pg_class pc, pg_catalog.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_catalog.pg_class pc, pg_catalog.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;
        -- extensions (only if necessary; keep them normally)
        FOR r IN (SELECT pns.nspname, pe.extname
                FROM pg_catalog.pg_extension pe, pg_catalog.pg_namespace pns
                WHERE pns.oid=pe.extnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
            ) LOOP
                EXECUTE format('DROP EXTENSION %I;', r.extname);
        END LOOP;
        -- aggregate functions first (because they depend on other functions)
        FOR r IN (SELECT pns.nspname, pp.proname, pp.oid
                FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns, pg_catalog.pg_aggregate pagg
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pagg.aggfnoid=pp.oid
            ) LOOP
                EXECUTE format('DROP AGGREGATE %I.%I(%s);',
                    r.nspname, r.proname,
                    pg_get_function_identity_arguments(r.oid));
        END LOOP;
        -- routines (functions, aggregate functions, procedures, window functions)
        IF EXISTS (SELECT * FROM pg_catalog.pg_attribute
                WHERE attrelid='pg_catalog.pg_proc'::regclass
                    AND attname='prokind' -- PostgreSQL 11+
            ) THEN
                q := 'CASE pp.prokind
                        WHEN ''p'' THEN ''PROCEDURE''
                        WHEN ''a'' THEN ''AGGREGATE''
                        ELSE ''FUNCTION''
                    END';
        ELSIF EXISTS (SELECT * FROM pg_catalog.pg_attribute
                WHERE attrelid='pg_catalog.pg_proc'::regclass
                    AND attname='proisagg' -- PostgreSQL ≤10
            ) THEN
                q := 'CASE pp.proisagg
                        WHEN true THEN ''AGGREGATE''
                        ELSE ''FUNCTION''
                    END';
        ELSE
                q := '''FUNCTION''';
        END IF;
        FOR r IN EXECUTE 'SELECT pns.nspname, pp.proname, pp.oid, ' || q || ' AS pt
                FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN (''information_schema'', ''pg_catalog'', ''pg_toast'')
            ' LOOP
                EXECUTE format('DROP %s %I.%I(%s);', r.pt,
                    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_catalog.pg_namespace pns, pg_catalog.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; $$;

Testato, tranne aggiunte successive ( extensionsfornite da Clément Prévost ), su PostgreSQL 9.6 ( jessie-backports). Rimozione aggregata testata su 9.6 e 12.2, rimozione della procedura testata anche su 12.2. Bugfix e ulteriori miglioramenti sono benvenuti!


Perfetto, ecco il mio codice per le estensioni, deve essere posizionato prima delle funzioni / procedure: - estensioni FOR r IN (SELEZIONA pns.nspname, pe.extname DA pg_extension pe, pg_namespace pns DOVE pns.oid = pe.extnamespace E pns .nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')) Formato LOOP EXECUTE ('DROP EXTENSION% I;', r.extname); LOOP DI FINE;
Clément Prévost,

@ ClémentPrévost grazie, ho unito il tuo commento nel codice (spero di averlo fatto bene, i commenti mancano di formattazione, per favore rivedi). Di solito lascio volutamente le estensioni non cancellate deliberatamente (il mio caso d'uso è il ripristino da backup con diverse versioni dello schema e normalmente ho esattamente un'estensione, PL / pgSQL, caricata). Per alcuni potrebbe essere utile, quindi grazie!
mirabilos,

Perfetto, grazie :)
Clément Prévost,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.