Явные курсоры редко нужны в 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
и цитируемых именах таблиц:
Для многократного использования
Создайте «шаблонную» базу данных (назовем ее my_template
) с вашей ванильной структурой и всеми пустыми таблицами. Затем выполните цикл DROP
/ CREATE DATABASE
:
DROP DATABASE mydb;
CREATE DATABASE mydb <b>TEMPLATE my_template</b>;
Это чрезвычайно быстро , поскольку Postgres копирует всю структуру на уровне файлов. Нет проблем с параллелизмом или другими накладными расходами, замедляющими вас.
Если одновременные соединения не позволяют вам сбросить БД, подумайте: