Postgres veritabanındaki tüm tabloları kesme


155

Yeniden yapılandırmadan önce düzenli olarak PostgreSQL veritabanımdaki tüm verileri silmem gerekiyor. Bunu doğrudan SQL'de nasıl yapabilirim?

Şu anda yürütmem gereken tüm komutları döndüren bir SQL ifadesi ile gelmeyi başardım:

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

Ama bir kere sahip olduktan sonra onları programlı olarak yürütmenin bir yolunu göremiyorum.

Yanıtlar:


226

FrustratedWithFormsDesigner doğru, PL / pgSQL bunu yapabilir. İşte senaryo:

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;

Bu, daha sonra şu şekilde kullanabileceğiniz depolanmış bir işlev oluşturur (bunu yalnızca bir kez yapmanız gerekir):

SELECT truncate_tables('MYUSER');

1
Biraz reddetmek zorunda kaldı ama bundan sonra bir cazibe gibi çalıştı! Daha önce hiç plpgsql kullanmadım, bu beni yaşlandırırdı. Teşekkürler! İhtiyaç duyan herkes için bu yazının sonuna kadar kullandığım kodu ekledim.
Sig

Üzgünüz, muhtemelen Oracle PL / SQL'de düşünüyordum :( Yukarıdaki
kodumda

1
SELECT deyimini doğrudan FOR döngüsüne taşıyabilirsiniz. DECLARE r RECORD;sonra döngü için: FOR r IN SELECT tablename FROM pg_tables LOOP
Michael Buen

6
KAMYON

3
AMAN TANRIM!! Ben sadece "ortak" şema tüm tablolarımı kesilmiş .... pls "şema" başka bir parametre eklemek böylece fonksiyon sadece sağlanan şema üzerinde tabloları keser!
roneo

95

Plpgsql'de açık imleçlere nadiren ihtiyaç duyulur. Bir döngünün daha basit ve daha hızlı örtük imlecini kullanın FOR:

Not: Tablo adları veritabanı başına benzersiz olmadığından, emin olmak için tablo adlarını şema nitelemelisiniz. Ayrıca, işlevi varsayılan şema 'genel' ile sınırlandırıyorum. Gereksinimlerinize uyum sağlayın, ancak sistem şemalarını pg_*ve hariç tuttuğunuzdan emin olun information_schema.

Be çok dikkatli bu işlevlerle. Onlar veritabanı nuke. Bir çocuk güvenlik cihazı ekledim. Comment RAISE NOTICEhattı ve yorumsuz EXECUTEasal bomba ...

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()Postgres 9.1 veya üstünü gerektirir. Eski sürümlerde sorgu dizesini şu şekilde birleştirin:

'TRUNCATE TABLE ' || quote_ident(_sch) || '.' || quote_ident(_tbl)  || ' CASCADE';

Tek komut, döngü yok

Aynı anda TRUNCATEbirden fazla tablo yapabileceğimizden, imleç veya döngüye hiç ihtiyacımız yok:

Tüm tablo adlarını toplayın ve tek bir deyim yürütün. Daha basit, daha hızlı:

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;

Aramak:

SELECT truncate_tables('postgres');

Hassaslaştırılmış sorgu

Bir işleve bile ihtiyacınız yok. Postgres 9.0 ve sonraki sürümlerinde bir DOdeyimde dinamik komutları yürütebilirsiniz . Postgres 9.5 ve sonraki sürümlerde sözdizimi daha da basit olabilir:

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

Arasındaki fark hakkında pg_class, pg_tablesve information_schema.tables:

regclassTablo adları hakkında ve alıntılanan tablo adları:

Tekrarlanan kullanım için

Vanilya yapınız ve tüm boş tablolarınızla bir "şablon" veritabanı oluşturun (adını verelim my_template). Sonra bir DROP/CREATE DATABASE döngüsü geçirin:

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

Bu son derece hızlıdır , çünkü Postgres tüm yapıyı dosya düzeyinde kopyalar. Eşzamanlılık sorunları veya başka ek yükler sizi yavaşlatmaz.

Eşzamanlı bağlantılar DB'yi bırakmanıza engel oluyorsa şunları göz önünde bulundurun:


1
Bu son işlevin TÜM veritabanlarını sildiğini belirtmek gerekir. Sadece şu anda bağlı olan değil .... evet ... bana naiive de olsa bu gerçekten bu yazıdan net değildi.
Amalgovinus

@Amalgovinus: Hangi son işlev? Cevabımdaki işlevlerin hiçbiri geçerli veritabanı dışındaki herhangi bir şeye dokunmuyor ( DROP DATABASE mydbtabii ki hariç ). Şemaları veritabanlarıyla karıştırıyor olabilir misiniz ?
Erwin Brandstetter

3
@Amalgovinus: Hayır, bu imkansız. DOKomutu (başka bir SQL ifadesinden gibi) geçerli veritabanında yürütülür münhasıran . Postgres'in aynı işlemdeki diğer veritabanlarına erişmesi mümkün değildir. Bunu yapmak için dblink veya FDW kullanmanız gerekir. Ama does eklemek sürece - Geçerli veritabanındaki tüm şemaları etkileyen WHERE t.schemaname = 'public'bu özel durumda belirli bir şemaya etkisini sınırlamak için.
Erwin Brandstetter

1
Bu şablonlar hakkında bilmek gerçekten çok güzel. Bu, bir veritabanı sıfırlama / hazırlamanın gerekli olabileceği otomatik test senaryolarında bile yararlı olabilir.
hbobenicio

3
Mükemmel cevap için teşekkürler, ben TRUNCATE komutunu döndürür "Tek komut, döngü yok" kullanıyorum, nasıl yürütme hakkında gitmek gerekir?
Mahyar

40

Bunu yapmak zorunda, ben sadece geçerli db bir şema sql oluşturmak, sonra damla ve db oluşturmak, sonra şema sql ile db yükleyeceğim.

İlgili adımlar şunlardır:

1) Şema veritabanı dökümü oluşturun ( --schema-only)

pg_dump mydb -s > schema.sql

2) Veritabanını bırakın

drop database mydb;

3) Veritabanı Oluşturun

create database mydb;

4) İthalat Şeması

psql mydb < schema.sql


9

Bu durumda, şablon olarak kullandığınız boş bir veritabanına sahip olmak daha iyi olur ve yenilemeniz gerektiğinde, mevcut veritabanını bırakın ve şablondan yeni bir veritabanı oluşturun.



3

Bunu bash ile de yapabilirsiniz:

#!/bin/bash
PGPASSWORD='' psql -h 127.0.0.1 -Upostgres sng --tuples-only --command "SELECT 'TRUNCATE TABLE ' || schemaname || '.' ||  tablename || ';' FROM pg_tables WHERE schemaname in ('cms_test', 'ids_test', 'logs_test', 'sps_test');" | 
tr "\\n" " " | 
xargs -I{} psql -h 127.0.0.1 -Upostgres sng --command "{}"

Şema adlarınızı, parolalarınızı ve kullanıcı adlarınızı şemalarınızla eşleşecek şekilde ayarlamanız gerekir.


3

Temizlik AUTO_INCREMENTversiyonu:

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

        IF EXISTS (
            SELECT column_name 
            FROM information_schema.columns 
            WHERE table_name=quote_ident(stmt.tablename) and column_name='id'
        ) THEN
           EXECUTE 'ALTER SEQUENCE ' || quote_ident(stmt.tablename) || '_id_seq RESTART WITH 1';
        END IF;

    END LOOP;
END;
$$ LANGUAGE plpgsql;

3

Çocuklar daha iyi ve temiz bir yol:

1) Şema veritabanı dökümü oluşturun (yalnızca - schema) pg_dump mydb -s> schema.sql

2) Bırak veritabanı bırak veritabanı mydb;

3) Veritabanı oluşturmak veritabanı mydb oluşturmak;

4) İthalat Şeması psql mydb <schema.sql

Benim için çalışıyor!

İyi günler. Hiram Walker


2

Eğer kullanabiliyorsa psql'i kullanabileceğiniz \gexecsorgu çıktı yürütmek için meta komutu;

SELECT
    format('TRUNCATE TABLE %I.%I', ns.nspname, c.relname)
  FROM pg_namespace ns 
  JOIN pg_class c ON ns.oid = c.relnamespace
  JOIN pg_roles r ON r.oid = c.relowner
  WHERE
    ns.nspname = 'table schema' AND                               -- add table schema criteria 
    r.rolname = 'table owner' AND                                 -- add table owner criteria
    ns.nspname NOT IN ('pg_catalog', 'information_schema') AND    -- exclude system schemas
    c.relkind = 'r' AND                                           -- tables only
    has_table_privilege(c.oid, 'TRUNCATE')                        -- check current user has truncate privilege
  \gexec 

\gexec9.6 sürümüne eklenen not


1

Verileri kaldırmak ve pgAdmin'de tablo yapılarını korumak için şunları yapabilirsiniz:

  • Veritabanına sağ tıklayın -> yedekleyin, "Yalnızca şema" yı seçin
  • Veritabanını bırak
  • Yeni bir veritabanı oluşturun ve eskisi gibi adlandırın
  • Yeni veritabanını sağ tıklayın -> geri yükle -> yedeklemeyi seçin, "Yalnızca şema" yı seçin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.