Явні курсори рідко потрібні в 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 копіює всю структуру на рівні файлів. Жодні проблеми з одночасністю чи інші накладні сповільнюють вас.
Якщо паралельні з'єднання не дають вам скидати БД, врахуйте: