[英]Truncating all tables in a Postgres database
在重建之前,我经常需要从我的 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
-- 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()
需要 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
-- 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;
称呼:
SELECT truncate_tables('postgres');
你甚至不需要一个函数。 在 Postgres 9.0+ 中,您可以在DO
语句中执行动态命令。 在 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$;
关于pg_class
、 pg_tables
和information_schema.tables
的区别:
关于regclass
和引用的表名:
使用您的vanilla 结构和所有空表创建一个“模板”数据库(让我们将其命名为my_template
)。 然后通过DROP
/CREATE DATABASE
循环:
DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;
这非常快,因为 Postgres 在文件级别复制整个结构。 没有并发问题或其他开销会减慢您的速度。
如果并发连接阻止您删除数据库,请考虑:
如果我必须这样做,我将简单地创建当前数据库的模式 sql,然后删除并创建数据库,然后使用模式 sql 加载数据库。
以下是涉及的步骤:
1)创建数据库的模式转储( --schema-only
)
pg_dump mydb -s > schema.sql
2) 删除数据库
drop database mydb;
3) 创建数据库
create database mydb;
4) 导入架构
psql mydb < schema.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) || '';
END LOOP;
END $$;
伙计们,更好、更干净的方法是:
1)创建数据库的模式转储(--schema-only)pg_dump mydb -s > schema.sql
2) drop database drop database mydb;
3)创建数据库create database mydb;
4) 导入 Schema psql mydb < schema.sql
这对我有用!
祝你今天过得愉快。 海拉姆·沃克
能不能用动态SQL依次执行每条语句? 您可能必须编写一个 PL/pgSQL 脚本来执行此操作。
http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html (第 38.5.4 节。执行动态命令)
清理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;
你也可以用 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 "{}"
您将需要调整架构名称、密码和用户名以匹配您的架构。
如果你可以使用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
注意\\gexec
是在 9.6 版本中引入的
很简单,你可以运行这段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 $$;
要在pgAdmin 中删除数据并保留表结构,您可以执行以下操作:
您可以使用类似的方法来获取所有截断查询。
SELECT 'TRUNCATE TABLE ' || table_name || ';'
FROM information_schema.tables
WHERE table_schema='schema_name'
AND table_type='BASE TABLE';
我在这里看不到的一件事是截断然后重置序列。 请注意,像此处给出的所有内容一样的简单截断只会截断表,但会将序列保留为其截断前的值。 要在截断时将序列重置为其起始值,请执行以下操作:
TRUNCATE TABLE table_name RESTART IDENTITY CASCADE;
您可以将该 RESTART IDENTITY 添加到您喜欢的任何答案中,无需在此处重复。 CASCADE 适用于您可能面临的任何外键约束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.