我经常需要在重建之前删除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;
这会创建一个存储的函数(您只需要执行一次),然后您可以像这样使用它:
SELECT truncate_tables('MYUSER');
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_class
,pg_tables
和information_schema.tables
之间的区别:
关于regclass
和引用的表名:
使用您的vanilla结构和所有空表创建一个“模板”数据库(让我们将其命名为my_template
)。然后通过DROP
/ CREATE DATABASE
循环:
DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;
这非常快,因为Postgres在文件级别复制整个结构。没有并发问题或其他开销会降低您的速度。
如果并发连接阻止您丢弃数据库,请考虑:
如果我必须这样做,我将只创建一个当前db的模式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
在这种情况下,最好只有一个用作模板的空数据库,当您需要刷新时,删除现有数据库并从模板中创建一个新数据库。
您可以使用动态SQL依次执行每个语句吗?您可能必须编写PL / pgSQL脚本来执行此操作。
http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html(第38.5.4节。执行动态命令)
您也可以使用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 "{}"
您需要调整模式名称,密码和用户名以匹配您的模式。
清洁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;
要删除数据并保留pgAdmin中的表结构,您可以执行以下操作:
伙计们更好更干净的方法是:
1)创建数据库的模式转储(--schema-only)pg_dump mydb -s> schema.sql
2)删除数据库丢弃数据库mydb;
3)创建数据库创建数据库mydb;
4)导入模式psql mydb <schema.sql
这对我有用!
祝你今天愉快。希拉姆沃克