在 plpgsql 中很少需要显式游标。使用FOR 循环中更简单、更快速的隐式光标:
注意:由于每个数据库的表名不是唯一的,因此您必须对表名进行模式限定以确保。此外,我将功能限制为默认模式“公共”。适应您的需求,但请务必排除系统架构 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 和引用的表名:
重复使用
使用您的原版结构和所有空表创建一个“模板”数据库(我们将其命名为my_template)。然后经过一个DROP/CREATE DATABASE循环:
DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;
这是非常快,因为 Postgres 在文件级别复制整个结构。没有并发问题或其他开销减慢您的速度。
如果并发连接阻止您删除数据库,请考虑: