Postgresデータベースのすべてのテーブルを切り捨てる


155

再構築する前に、PostgreSQLデータベースからすべてのデータを定期的に削除する必要があります。これをSQLで直接行うにはどうすればよいですか?

現時点では、実行する必要のあるすべてのコマンドを返すSQLステートメントを考え出すことができました。

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

しかし、それらを取得したら、プログラムで実行する方法がわかりません。

回答:


226

FrustratedWithFormsDesignerは正しいです、PL / pgSQLはこれを行うことができます。スクリプトは次のとおりです。

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;

これは、後で次のように使用できるストアド関数を作成します(これは一度だけ実行する必要があります)。

SELECT truncate_tables('MYUSER');

1
少し揺り動かさなければならなかったが、その後それは魅力のように働いた!私は以前にpgpgsqlを使用したことがないので、これには年齢がかかります。ありがとう!それを必要とする人のために、この記事の最後に使用したコードを追加しました。
Sig

。申し訳ありませんが、私はおそらく、OracleのPL / SQL :(私は上記の私のコードで構文エラーを修正して考えていた
ヘニング

1
SELECTステートメントを直接FORループに移動することもできます。 DECLARE r RECORD;その後forループ: FOR r IN SELECT tablename FROM pg_tables LOOP
Michael Buen

6
CASCADEをTRUNCATE TABLEに追加します
Bogdan Gusiev 2010年

3
ああ、神様!!「パブリック」スキーマ内のすべてのテーブルを切り捨てただけです。plsは「スキーマ」の別のパラメーターを追加し、関数が提供されたスキーマでのみテーブルを切り捨てるようにします。
roneo

95

明示的なカーソルがplpgsqlで必要になることはほとんどありません。ループのより単純で高速な暗黙カーソルを使用しFORます。

注:テーブル名はデータベースごとに一意ではないため、確実にスキーマ名を付けてテーブル名を指定する必要があります。また、関数をデフォルトのスキーマ「public」に制限しています。ニーズに適応しますが、システムスキーマpg_*とは必ず除外してくださいinformation_schema

ことは非常に慎重にこれらの機能を持ちます。彼らはあなたのデータベースを核にします。子供の安全装置を追加しました。コメントRAISE NOTICE行とコメント解除EXECUTEプライムに爆弾を...

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以降が必要です。古いバージョンでは、次のようにクエリ文字列を連結します。

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

単一コマンド、ループなし

TRUNCATE一度に複数のテーブルを作成できるため、カーソルやループはまったく必要ありません。

すべてのテーブル名を集計し、単一のステートメントを実行します。シンプルで高速:

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;

コール:

SELECT truncate_tables('postgres');

洗練されたクエリ

関数も必要ありません。Postgres 9.0以降では、DOステートメント内で動的コマンドを実行できます。また、Postgres 9.5以降では、構文がさらにシンプルになります。

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

違いについてpg_classpg_tablesそしてinformation_schema.tables

regclass引用されたテーブル名について:

繰り返し使用する場合

バニラ構造とすべての空のテーブルを使用して「テンプレート」データベース(名前を付けましょうmy_template)を作成します。次に、DROP/CREATE DATABASEサイクルを実行します。

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

Postgresは構造全体をファイルレベルでコピーするため、これは非常に高速です。同時実行の問題やその他のオーバーヘッドにより、速度が低下することはありません。

同時接続によってDBをドロップできない場合は、以下を検討してください。


1
この最後の関数がすべてのデータベースをワイプしたことは注目に値します。現在接続されているものだけではありません...そうです...私をナイーブと呼んでください。しかし、それはこの投稿からははっきりしていませんでした。
Amalgovinus

@Amalgovinus:最後の機能はどれですか?私の回答の関数はどれも、現在のデータベースの外には触れていません(DROP DATABASE mydb明らかにを除く)。スキーマとデータベースを混同していますか?
Erwin Brandstetter 2015

3
@Amalgovinus:いいえ、それは不可能です。DO(他のSQL文のような)コマンドは、現在のデータベースで実行され、排他的。Postgresは同じトランザクションで他のデータベースにアクセスする方法がありません。そのためには、dblinkまたはFDWを使用する必要があります。しかし、それはありませんあなたが追加しない限り-現在のデータベース内のすべてのスキーマに影響を与えWHERE t.schemaname = 'public'、この特定のケースではある特定のスキーマへの影響を制限します。
Erwin Brandstetter、2015

1
それらのテンプレートについて知って本当に良かったです。これは、データベースのリセット/準備が必要になる可能性がある自動テストシナリオでも役立ちます。
hbobenicio 2017年

3
すばらしい回答をありがとう、私はTRUNCATEコマンドを返す「単一コマンド、ループなし」を使用していますが、それを実行するにはどうすればよいですか?
Mahyar 2018年

40

これを行う必要がある場合は、現在のdbのスキーマsqlを作成してから、dbをドロップして作成し、スキーマsqlでdbをロードします。

以下は関連するステップです:

1)データベースのスキーマダンプを作成します(--schema-only

pg_dump mydb -s > schema.sql

2)データベースを削除する

drop database mydb;

3)データベースを作成する

create database mydb;

4)スキーマのインポート

psql mydb < schema.sql


9

この場合、テンプレートとして使用する空のデータベースを用意し、更新する必要がある場合は、既存のデータベースを削除して、テンプレートから新しいデータベースを作成することをお勧めします。



3

あなたはbashでもこれを行うことができます:

#!/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 "{}"

スキーマに一致するように、スキーマ名、パスワード、およびユーザー名を調整する必要があります。


3

クリーニングAUTO_INCREMENTバージョン:

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

みんなより良くてきれいな方法は:

1)データベースのスキーマダンプを作成します(-スキーマのみ)pg_dump mydb -s> schema.sql

2)ドロップデータベースドロップデータベースmydb;

3)データベースの作成データベースmydbを作成します。

4)スキーマのインポートpsql mydb <schema.sql

それは私のために働いています!

ごきげんよう。ハイラムウォーカー


2

あなたが使用できる場合はpsqlを、あなたは使用することができ\gexec、クエリの出力を実行するためのメタコマンドを。

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 

\gexecバージョン9.6で導入されたことに注意してください。


1

データを削除し、pgAdminのテーブル構造を維持するには、次のようにします。

  • データベースを右クリック->バックアップ、「スキーマのみ」を選択
  • データベースを削除する
  • 新しいデータベースを作成し、前者のように名前を付けます
  • 新しいデータベースを右クリック->復元->バックアップを選択し、「スキーマのみ」を選択します
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.