简体   繁体   English

截断 Postgres 数据库中的所有表

[英]Truncating all tables in a Postgres database

I regularly need to delete all the data from my PostgreSQL database before a rebuild.在重建之前,我经常需要从我的 PostgreSQL 数据库中删除所有数据。 How would I do this directly in SQL?我将如何直接在 SQL 中执行此操作?

At the moment I've managed to come up with a SQL statement that returns all the commands I need to execute:目前我已经想出了一个 SQL 语句,它返回我需要执行的所有命令:

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

But I can't see a way to execute them programmatically once I have them.但是一旦拥有它们,我就看不到以编程方式执行它们的方法。

FrustratedWithFormsDesigner is correct, PL/pgSQL can do this. FrustratedWithFormsDesigner 是正确的,PL/pgSQL 可以做到这一点。 Here's the script:这是脚本:

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;

This creates a stored function (you need to do this just once) which you can afterwards use like this:这将创建一个存储函数(您只需要执行一次),之后您可以像这样使用它:

SELECT truncate_tables('MYUSER');

Explicit cursors are rarely needed in plpgsql. plpgsql 中很少需要显式游标。 Use the simpler and faster implicit cursor of a FOR loop:使用FOR循环的更简单、更快的隐式游标

Note: Since table names are not unique per database, you have to schema-qualify table names to be sure.注意:由于每个数据库的表名不是唯一的,因此您必须对表名进行模式限定才能确定。 Also, I limit the function to the default schema 'public'.此外,我将该功能限制为默认模式“public”。 Adapt to your needs, but be sure to exclude the system schemas pg_* and information_schema .适应您的需求,但一定要排除系统架构pg_*information_schema

Be very careful with these functions.使用这些功能时要非常小心 They nuke your database.他们核爆你的数据库。 I added a child safety device.我加了一个儿童安全装置。 Comment the RAISE NOTICE line and uncomment EXECUTE to prime the bomb ...注释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  
      -- dangerous, test before you execute!
      RAISE NOTICE '%',  -- once confident, comment this line ...
      -- EXECUTE         -- ... and uncomment this one
         format('TRUNCATE TABLE %I.%I CASCADE', _sch, _tbl);
   END LOOP;
END
$func$ LANGUAGE plpgsql;

format() requires Postgres 9.1 or later. format()需要 Postgres 9.1 或更高版本。 In older versions concatenate the query string like this:在旧版本中,像这样连接查询字符串:

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

Single command, no loop单命令,无循环

Since we can TRUNCATE multiple tables at once we don't need any cursor or loop at all:由于我们可以一次TRUNCATE多个表,我们根本不需要任何游标或循环:

Aggregate all table names and execute a single statement.聚合所有表名并执行单个语句。 Simpler, faster:更简单、更快:

CREATE OR REPLACE FUNCTION f_truncate_tables(_username text)
  RETURNS void AS
$func$
BEGIN
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
  (SELECT 'TRUNCATE TABLE '
       || string_agg(format('%I.%I', schemaname, tablename), ', ')
       || ' CASCADE'
   FROM   pg_tables
   WHERE  tableowner = _username
   AND    schemaname = 'public'
   );
END
$func$ LANGUAGE plpgsql;

Call:称呼:

SELECT truncate_tables('postgres');

Refined query细化查询

You don't even need a function.你甚至不需要一个函数。 In Postgres 9.0+ you can execute dynamic commands in a DO statement.在 Postgres 9.0+ 中,您可以在DO语句中执行动态命令。 And in Postgres 9.5+ the syntax can be even simpler:在 Postgres 9.5+ 中,语法可以更简单:

DO
$func$
BEGIN
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
   (SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
    FROM   pg_class
    WHERE  relkind = 'r'  -- only tables
    AND    relnamespace = 'public'::regnamespace
   );
END
$func$;

About the difference between pg_class , pg_tables and information_schema.tables :关于pg_classpg_tablesinformation_schema.tables的区别:

About regclass and quoted table names:关于regclass和引用的表名:

For repeated use重复使用

Create a "template" database (let's name it my_template ) with your vanilla structure and all empty tables.使用您的vanilla 结构和所有空表创建一个“模板”数据库(让我们将其命名为my_template )。 Then go through a DROP /CREATE DATABASE cycle:然后通过DROP /CREATE DATABASE循环:

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

This is extremely fast , because Postgres copies the whole structure on the file level.非常,因为 Postgres 在文件级别复制整个结构。 No concurrency issues or other overhead slowing you down.没有并发问题或其他开销会减慢您的速度。

If concurrent connections keep you from dropping the DB, consider:如果并发连接阻止您删除数据库,请考虑:

If I have to do this, I will simply create a schema sql of current db, then drop & create db, then load db with schema sql.如果我必须这样做,我将简单地创建当前数据库的模式 sql,然后删除并创建数据库,然后使用模式 sql 加载数据库。

Below are the steps involved:以下是涉及的步骤:

1) Create Schema dump of database ( --schema-only ) 1)创建数据库的模式转储( --schema-only

pg_dump mydb -s > schema.sql

2) Drop database 2) 删除数据库

drop database mydb;

3) Create Database 3) 创建数据库

create database mydb;

4) Import Schema 4) 导入架构

psql mydb < schema.sql

在这种情况下,最好只使用一个空数据库作为模板,当您需要刷新时,删除现有数据库并从模板创建一个新数据库。

Just execute the query bellow:只需执行下面的查询:

DO $$ DECLARE
    r RECORD;
BEGIN
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || '';
    END LOOP;
END $$;

Guys the better and clean way is to :伙计们,更好、更干净的方法是:

1) Create Schema dump of database (--schema-only) pg_dump mydb -s > schema.sql 1)创建数据库的模式转储(--schema-only)pg_dump mydb -s > schema.sql

2) Drop database drop database mydb; 2) drop database drop database mydb;

3) Create Database create database mydb; 3)创建数据库create database mydb;

4) Import Schema psql mydb < schema.sql 4) 导入 Schema psql mydb < schema.sql

It´s work for me!这对我有用!

Have a nice day.祝你今天过得愉快。 Hiram Walker海拉姆·沃克

Could you use dynamic SQL to execute each statement in turn?能不能用动态SQL依次执行每条语句? You would probably have to write a PL/pgSQL script to do this.您可能必须编写一个 PL/pgSQL 脚本来执行此操作。

http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html (section 38.5.4. Executing Dynamic Commands) http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html (第 38.5.4 节。执行动态命令)

Cleaning AUTO_INCREMENT version:清理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;

You can do this with bash also:你也可以用 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 "{}"

You will need to adjust schema names, passwords and usernames to match your schemas.您将需要调整架构名称、密码和用户名以匹配您的架构。

If you can use psql you can use \\gexec meta command to execute query output;如果你可以使用psql你可以使用\\gexec meta 命令来执行查询输出;

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 

Note that \\gexec is introduced into the version 9.6注意\\gexec是在 9.6 版本中引入的

Simply, you can run this piece of SQL:很简单,你可以运行这段SQL:

DO $$ DECLARE
  r RECORD;
BEGIN
  FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname =current_schema()) LOOP
    EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || ' CASCADE';
  END LOOP;
END $$;

For removing the data and preserving the table-structures in pgAdmin you can do:要在pgAdmin 中删除数据并保留表结构,您可以执行以下操作:

  • Right-click database -> backup, select "Schema only"右键数据库->备份,选择“Schema only”
  • Drop the database删除数据库
  • Create a new database and name it like the former创建一个新的数据库并像前者一样命名
  • Right-click the new database -> restore -> select the backup, select "Schema only"右键新建数据库->恢复->选择备份,选择“Schema only”

You can use something like this to get all truncate queries.您可以使用类似的方法来获取所有截断查询。

SELECT 'TRUNCATE TABLE ' ||  table_name || ';' 
  FROM information_schema.tables
 WHERE table_schema='schema_name'
   AND table_type='BASE TABLE';

One thing that I don't see here is truncating and then resetting sequences.我在这里看不到的一件事是截断然后重置序列。 Note that a simple truncate like all that have been given here will just truncate the tables, but will leave sequences at their pre-truncate values.请注意,像此处给出的所有内容一样的简单截断只会截断表,但会将序列保留为其截断前的值。 To reset the sequences to their start values when you truncate do:要在截断时将序列重置为其起始值,请执行以下操作:

TRUNCATE TABLE table_name RESTART IDENTITY CASCADE;

you can just add that RESTART IDENTITY to any of the answers you fancy, no need to repeat that here.您可以将该 RESTART IDENTITY 添加到您喜欢的任何答案中,无需在此处重复。 CASCADE is there for any foreign key constraints you may face. CASCADE 适用于您可能面临的任何外键约束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM