截断Postgres数据库中的所有表

我经常需要在重build之前从我的PostgreSQL数据库中删除所有的数据。 我将如何直接在SQL中做到这一点?

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

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

但是我看不到一种方法来一旦我拥有它们就可以通过编程来执行它们。

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; 

这将创build一个存储函数(您只需要这样做一次),然后您可以像这样使用它:

 SELECT truncate_tables('MYUSER'); 

显式游标在plpgsql中是很less需要的。 只需使用FOR循环中更简单,更快的隐式游标即可

注意:由于每个数据库的表名不唯一,因此必须对表名进行模式限定。 另外,我将函数限制为默认模式“public”。 适应您的需求,但一定要排除系统模式pg_*information_schema

对这些function要非常小心 。 他们核弹你的数据库。 我加了一个儿童安全装置。 评论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或更高版本。 在较旧的版本中,像这样连接查询string:

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

精致的查询

你甚至不需要一个function。 在Postgres 9.0+中,您可以在DO语句中执行dynamic命令。 而在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和引用的表名:

  • 表名称作为PostgreSQL函数参数

重复使用

使用vanilla结构和所有空表创build“模板”数据库(让我们将其命名为my_template )可能会更简单(更快)。 然后经历一个DROP / CREATE DATABASE循环:

 DROP DATABASE mydb; CREATE DATABASE mydb TEMPLATE my_template ; 

这是非常快的 ,因为Postgres在文件级复制整个结构。 没有并发问题或其他开销减慢你。

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

以下是涉及的步骤:

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

pg_dump mydb -s > schema.sql

2)删除数据库

drop database mydb;

3)创build数据库

create database mydb;

4)导入架构

psql mydb < schema.sql

在这种情况下,最好将一个空数据库用作模板,当您需要刷新时,放弃现有数据库并从模板创build一个新数据库。

你可以使用dynamicSQL依次执行每个语句吗? 你可能不得不写一个PL / pgSQL脚本来做到这一点。

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

你也可以用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 "{}" 

您将需要调整模式名称,密码和用户名以匹配您的模式。

为了移除数据并保留pgAdmin中的表结构,你可以这样做:

  • 右键单击数据库 – >备份,select“Schema only”
  • 删除数据库
  • 创build一个新的数据库并将其命名为前者
  • 右键单击新build数据库 – >恢复 – >select备份,select“Schema only”

清洗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;