截断Postgres数据库中的所有表

时间:2010-05-13 18:04:16

标签: postgresql plpgsql dynamic-sql truncate database-table

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

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

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

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

11 个答案:

答案 0 :(得分:194)

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 :(得分:80)

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_tablesinformation_schema.tables之间的差异:

关于regclass和引用的表名:

重复使用

使用您的vanilla结构和所有空表创建“模板”数据库(我们将其命名为my_template)。然后浏览 DROP / CREATE DATABASE 周期:

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

这是 非常,因为Postgres会在文件级别复制整个结构。没有并发问题或其他开销会让您失望。

如果并发连接阻止您丢弃数据库,请考虑:

答案 2 :(得分:31)

如果我必须这样做,我将简单地创建一个当前数据库的模式sql,然后删除&创建db,然后使用schema sql加载db。

以下是所涉及的步骤:

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

pg_dump mydb -s > schema.sql

2)删除数据库

drop database mydb;

3)创建数据库

create database mydb;

4)导入架构

psql mydb < schema.sql

答案 3 :(得分:9)

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

答案 4 :(得分:3)

您可以使用动态SQL依次执行每个语句吗?您可能必须编写PL / pgSQL脚本来执行此操作。

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

答案 5 :(得分: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 "{}"

您需要调整架构名称,密码和用户名以匹配您的架构。

答案 6 :(得分:3)

清理VerifyError版本:

AUTO_INCREMENT

答案 7 :(得分:2)

要删除数据并保留documentation中的表结构,您可以执行以下操作:

  • 右键单击数据库 - &gt;备份,选择“仅架构”
  • 删除数据库
  • 创建一个新数据库并将其命名为前者
  • 右键单击新数据库 - &gt;恢复 - &gt;选择备份,选择“仅架构”

答案 8 :(得分:2)

伙伴们更好更干净的方法是:

1)创建数据库的Schema转储(仅限--schema) pg_dump mydb -s&gt; schema.sql文件

2)删除数据库 drop database mydb;

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

4)导入架构 psql mydb&lt; schema.sql文件

对我有用!

祝你有个愉快的一天。 希拉姆沃克

答案 9 :(得分: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版

答案 10 :(得分:1)

只需执行以下查询:

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