Cursores explícitos raramente são necessários no plpgsql. Use o cursor implícito mais simples e rápido de um FOR
loop:
Nota: Como os nomes das tabelas não são exclusivos por banco de dados, é necessário qualificar os nomes das tabelas para garantir o esquema. Além disso, limito a função ao esquema padrão 'público'. Adapte-se às suas necessidades, mas certifique-se de excluir os esquemas do sistema pg_*
e information_schema
.
Tenha muito cuidado com essas funções. Eles danificam seu banco de dados. Eu adicionei um dispositivo de segurança infantil. Comente a RAISE NOTICE
linha e descomente EXECUTE
para preparar a bomba ...
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()
requer o Postgres 9.1 ou posterior. Nas versões mais antigas, concatenar a cadeia de consulta da seguinte maneira:
'TRUNCATE TABLE ' || quote_ident(_sch) || '.' || quote_ident(_tbl) || ' CASCADE';
Comando único, sem loop
Como podemos criar TRUNCATE
várias tabelas ao mesmo tempo, não precisamos de nenhum cursor ou loop:
Agregue todos os nomes de tabela e execute uma única instrução. Mais simples, mais rápido:
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;
Ligar:
SELECT truncate_tables('postgres');
Consulta refinada
Você nem precisa de uma função. No Postgres 9.0+, você pode executar comandos dinâmicos em uma DO
instrução. E no Postgres 9.5+, a sintaxe pode ser ainda mais simples:
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$;
Sobre a diferença entre pg_class
, pg_tables
e information_schema.tables
:
Sobre regclass
e citou nomes de tabelas:
Para uso repetido
Crie um banco de dados "modelo" (vamos chamá-lo my_template
) com sua estrutura de baunilha e todas as tabelas vazias. Em seguida, passe por um ciclo DROP
/CREATE DATABASE
:
DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;
Isso é extremamente rápido , porque o Postgres copia toda a estrutura no nível do arquivo. Não há problemas de simultaneidade ou outras sobrecargas que o tornam mais lento.
Se conexões simultâneas impedirem que você elimine o banco de dados, considere: