Явные курсоры редко нужны в 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 TEMPLATE my_template;
Это очень быстро , потому что Postgres копирует всю структуру на уровне файлов. Никаких проблем с параллелизмом или других накладных расходов, замедляющих вас.
Если одновременные соединения не дают вам сбросить БД, подумайте: