Hapus semua data dalam database Postgres


14

Saya telah membuat dump db baru dari server produksi dengan --data-onlydan --column-insertsflag, jadi saya hanya punya banyak pernyataan untuk memasukkan data ketika melakukan restore pada server staging.

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

Bagaimana cara menghapus semua data dalam database server pentas terlebih dahulu, sebelum mengembalikan data dari dump produksi?

Saya ingin menghapus semua data saja sehingga saya tidak perlu drop dan membuat database dan semua itu. Saya hanya ingin menghapus data dan memasukkan data baru itu saja.

Saya tidak memiliki opsi untuk menjatuhkan dan membuat database karena beberapa alasan. Saya harus menghapus semua data dan hanya memasukkan saja, jadi apa pun yang diperlukan untuk menemukan cara melakukan ini, saya bersedia melakukannya, tetapi perlu bantuan untuk memulainya.

Saya juga perlu mengotomatiskan proses ini. Akan mengotomatiskan "dumping data dari production db", lalu "menghapus data pada staging db", dan kemudian "mengembalikan data ke staging db". Saya hanya perlu bantuan pada bagian "menghapus data tentang pementasan db".

Saya menjalankan PostgreSQL 9.5.2

Jawaban:


24

Anda tidak harus menjatuhkan basis data, itu sudah cukup untuk menjatuhkan semua objek dalam basis data. Ini bisa dilakukan menggunakan

drop owned by adminuser

Jika Anda kemudian membuat dump SQL termasuk create tablepernyataan (sehingga tanpa satu --data-onlyopsi) semuanya harus baik-baik.

Anda juga dapat menghapus --column-insertsmaka, yang akan membuat impor yang banyak lebih cepat.


Namun, jika Anda ingin menghapus semuanya, Anda bisa melakukannya dengan sedikit SQL dinamis:

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;
$$

Ini akan memotong semua tabel dalam skema publicdengan satu pernyataan yang juga akan berfungsi bahkan jika ada banyak batasan kunci asing yang menghubungkan semua tabel. Jika tabel Anda tersebar di beberapa skema, Anda perlu menambahkannya dalam wherekondisi.


saya melihat ... apakah itu melakukan hal yang sama seperti @ ypercube yang disebutkan di atas untuk menggunakan perintah ini TRUNCATE table1, table2, ... <list of all tables>;? apakah mereka berdua melakukan hal yang sama?
uberrebu

1
@ babababa: ya, jawaban saya hanya menghasilkan dan menjalankan pernyataan itu secara dinamis, jadi Anda tidak perlu mengetikkan semua nama tabel dan jika Anda menambahkan tabel baru itu akan secara otomatis dimasukkan.
a_horse_with_no_name

bagus hanya mencobanya dan berfungsi, @ ypercube one berfungsi juga ... terima kasih banyak
uberrebu

6

pg_restore memiliki flag --clean (atau mungkin --create) yang akan secara otomatis menghapus data sebelum menjalankan operasi ..

Dokumentasi yang Luar Biasa akan sangat membantu Anda ...

Hanya untuk memperjelas, jika itu membingungkan:

Bersihkan (jatuhkan) objek basis data sebelum membuatnya kembali. (Kecuali - jika ada - digunakan, ini mungkin menghasilkan beberapa pesan kesalahan yang tidak berbahaya, jika ada objek yang tidak ada dalam database tujuan.)

Ini tidak akan menghapus database aktual .. hanya tabel / tampilan / etc.

Jika, karena alasan tertentu, menjatuhkan dan membuat ulang tabel tidak dapat diterima, maka Anda harus membuatnya lebih banyak pekerjaan untuk secara manual membuat skrip yang membuat data onlydump dari sumber db, masalah TRUNCATEatau DELETEdalam database target, dan kemudian memuat dump data. Tidak ada cara cepat / licin untuk melakukan ini, sejauh yang saya ketahui.


akankah --clean flag HANYA menghapus data dan menjaga struktur database dan tabel tetap sama tetapi kosong?
uberrebu

Ini akan mengeluarkan drop table sebelum membuat tabel. Setiap tabel yang ada di file dump. Saya akan BERHARAP bahwa file dump berisi informasi untuk membuat ulang tabel persis seperti yang ada sebelumnya (termasuk FKeys, dll) .. Tapi itu benar-benar tergantung pada bagaimana Anda membuat file dump. Namun, karena Anda terus menyebutkan "pementasan", sepertinya apa yang benar-benar Anda cari adalah cara untuk mengisi tabel pementasan di gudang data dengan data dari db produksi. Jika itu tujuan Anda, file dump mungkin pendekatan yang salah ..
Joishi Bodio

bukan itu yang ingin saya lakukan, saya hanya ingin menghapus data..database dan struktur tabel akan tetap sama dan tidak tersentuh ... pertanyaan saya cukup jelas apa yang ingin saya lakukan, bahkan dari judul
uberrebu

Kemudian, maaf untuk mengatakan, solusi Anda akan jauh lebih sulit.
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;  

Kueri di atas akan menghasilkan kueri terpotong untuk semua tabel dalam database.


0

Catatan: jawaban saya adalah tentang menghapus tabel dan objek database lainnya; untuk menghapus semua data dalam tabel, yaitu memotong semua tabel , Endre Both telah memberikan pernyataan (eksekusi langsung) yang dijalankan dengan baik sebulan kemudian.

Untuk kasus-kasus di mana Anda tidak bisa hanya DROP SCHEMA public CASCADE;, DROP OWNED BY current_user;atau sesuatu, di sini adalah skrip SQL yang berdiri sendiri yang saya tulis, yang aman untuk transaksi (yaitu Anda dapat meletakkannya di antara BEGIN;dan baik ROLLBACK;untuk mengujinya atau COMMIT;untuk benar-benar melakukan perbuatan) dan membersihkan "semua" objek basis data ... baik, semua yang digunakan dalam basis data yang digunakan aplikasi kita atau yang dapat saya tambahkan dengan bijaksana, yaitu:

  • pemicu di atas meja
  • kendala pada tabel (FK, PK CHECK,, UNIQUE)
  • indeks
  • VIEWs (normal atau terwujud)
  • meja
  • urutan
  • rutinitas (fungsi agregat, fungsi, prosedur)
  • semua skema nōn-default (yaitu bukan publicatau DB-internal) “we” own: script berguna ketika dijalankan sebagai “bukan superuser basis data”; superuser dapat menghapus semua schemata (yang benar-benar penting masih secara eksplisit dikecualikan)
  • ekstensi (kontribusi pengguna tetapi biasanya saya sengaja membiarkannya)

Tidak jatuh adalah (beberapa disengaja; beberapa hanya karena saya tidak punya contoh dalam DB kami):

  • yang publicskema (misalnya untuk hal-hal ekstensi yang disediakan di dalamnya)
  • koleksi dan barang lokal lainnya
  • pemicu acara
  • hal-hal pencarian teks, ... (lihat di sini untuk hal-hal lain yang mungkin saya lewatkan)
  • peran atau pengaturan keamanan lainnya
  • jenis komposit
  • meja roti panggang
  • FDW dan tabel asing

Ini sangat berguna untuk kasus-kasus ketika dump yang ingin Anda pulihkan adalah versi skema database yang berbeda (misalnya dengan Debian dbconfig-common, Flyway atau Liquibase / DB-Manul) daripada database yang ingin Anda pulihkan.

Saya juga punya versi yang menghapus "semuanya kecuali dua tabel dan apa yang menjadi milik mereka" (urutan, diuji secara manual, maaf, saya tahu, membosankan) jika ada yang tertarik; perbedaannya kecil. Hubungi saya atau periksa repo ini jika tertarik.

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; $$;

Diuji, kecuali penambahan selanjutnya ( extensionsdisumbangkan oleh Clément Prévost ), di PostgreSQL 9.6 ( jessie-backports). Penghapusan agregat diuji pada 9.6 dan 12.2, penghapusan prosedur juga diuji pada 12.2. Selamat datang di perbaikan bug dan perbaikan lebih lanjut!


Sempurna, di sini adalah kode saya untuk ekstensi, itu harus ditempatkan sebelum fungsi / prosedur: - ekstensi UNTUK r IN (PILIH pns.nspname, pe.extname DARI pg_extension pe, pg_namespace pns WHERE pns.oid = pe.extnamespace DAN pns .nspname TIDAK DI ('information_schema', 'pg_catalog', 'pg_toast')) format LOOP EXECUTE ('DROP EXTENSION% I;', r.extname); AKHIR LOOP;
Clément Prévost

@ ClémentPrévost terima kasih, saya menggabungkan komentar Anda ke dalam kode (harap saya melakukannya dengan benar, komentar tidak memiliki format, silakan tinjau). Saya biasanya membiarkan ekstensi terhapus secara sengaja (kasus penggunaan saya memulihkan dari cadangan dengan versi skema yang berbeda, dan saya biasanya memiliki satu ekstensi, PL / pgSQL, dimuat). Ini mungkin berguna bagi beberapa orang, jadi, terima kasih!
mirabilos

Sempurna, terima kasih :)
Clément Prévost
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.