截断Postgres数据库中的所有表

Sig*_*Sig 142 postgresql truncate dynamic-sql plpgsql database-table

我经常需要在重建之前删除PostgreSQL数据库中的所有数据.我将如何直接在SQL中执行此操作?

目前我已经设法提出一个SQL语句,它返回我需要执行的所有命令:

SELECT 'TRUNCATE TABLE ' ||  tablename || ';' FROM pg_tables WHERE tableowner='MYUSER';
Run Code Online (Sandbox Code Playgroud)

但是,一旦拥有它们,我就无法以编程方式执行它们.

Hen*_*ing 206

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;
Run Code Online (Sandbox Code Playgroud)

这会创建一个存储的函数(您只需要执行一次),然后您可以像这样使用它:

SELECT truncate_tables('MYUSER');
Run Code Online (Sandbox Code Playgroud)

  • 我会将CASCADE添加到TRUNCATE TABLE (6认同)
  • 我的天啊!!我只是截断了“公共”模式中的所有表。...请添加另一个“ schema”参数,以便函数仅在提供的模式中截断表! (3认同)
  • 您还可以将 SELECT 语句直接移动到 FOR 循环。`DECLARE r RECORD;` 然后 for 循环:`FOR r IN SELECT tablename FROM pg_tables LOOP` (2认同)
  • @roneo 看到问题:数据库中的“所有表”! (2认同)

Erw*_*ter 86

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;
Run Code Online (Sandbox Code Playgroud)

format()需要Postgres 9.1或更高版本.在旧版本中连接查询字符串,如下所示:

'TRUNCATE TABLE ' || quote_ident(_sch) || '.' || quote_ident(_tbl)  || ' CASCADE';
Run Code Online (Sandbox Code Playgroud)

单一命令,无循环

由于我们可以同时使用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;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT truncate_tables('postgres');
Run Code Online (Sandbox Code Playgroud)

精炼查询

你甚至不需要一个功能.在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$;
Run Code Online (Sandbox Code Playgroud)

关于和之间的区别pg_class,pg_tablesinformation_schema.tables:

关于regclass和引用表名:

供重复使用

my_template用你的vanilla结构和所有空表创建一个"模板"数据库(让它命名)可能更简单,也更快.然后经过一个DROP/CREATE DATABASE周期:

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;
Run Code Online (Sandbox Code Playgroud)

非常,因为Postgres在文件级别复制整个结构.没有并发问题或其他开销会降低您的速度.

  • @Amalgovinus:不,那是不可能的.`DO`命令(与任何其他SQL语句一样)在当前数据库*中独占*.Postgres无法访问同一事务中的其他数据库.您必须使用dblink或FDW来执行此操作.但它确实*会影响当前数据库中的所有模式 - 除非你在这种特殊情况下添加`WHERE t.schemaname ='public'`来限制对一个特定模式的影响. (3认同)
  • 感谢您的出色回答,我使用的是“单命令,无循环”,该命令返回TRUNCATE命令,应该如何执行呢? (3认同)

San*_*ing 35

如果我必须这样做,我将只创建一个当前db的模式sql,然后删除并创建db,然后使用schema sql加载db.

以下是涉及的步骤:

1)创建数据库的Schema转储(--schema-only)

pg_dump mydb -s > schema.sql

2)删除数据库

drop database mydb;

3)创建数据库

create database mydb;

4)导入架构

psql mydb < schema.sql


Sco*_*ley 9

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


Con*_*yen 8

只需执行下面的查询:

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 $$;
Run Code Online (Sandbox Code Playgroud)

  • 我在第 5 行的模式中的几个表中有外键约束。 EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.表名) || '级联'; (2认同)

Emm*_*uni 7

我在这里没有看到的一件事是截断然后重置序列。请注意,像此处给出的所有内容一样的简单截断只会截断表,但会将序列保留为截断前的值。要在截断时将序列重置为其起始值,请执行以下操作:

TRUNCATE TABLE table_name RESTART IDENTITY CASCADE;
Run Code Online (Sandbox Code Playgroud)

您可以将 RESTART IDENTITY 添加到您喜欢的任何答案中,无需在此处重复。CASCADE 可以解决您可能面临的任何外键约束。


小智 7

简单地说,你可以运行这段 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 $$;
Run Code Online (Sandbox Code Playgroud)


小智 5

伙计们,更好、更干净的方法是:

\n\n

1) 创建数据库的架构转储 (--schema-only)\npg_dump mydb -s > schema.sql

\n\n

2) 删除数据库\n删除数据库 mydb;

\n\n

3) 创建数据库\n创建数据库mydb;

\n\n

4) 导入架构\npsql mydb < schema.sql

\n\n

它\xc2\xb4s 对我有用!

\n\n

祝你有美好的一天。\n海勒姆·沃克

\n