I cursori espliciti sono raramente necessari in plpgsql. Usa il cursore implicito più semplice e veloce di un FOR
loop:
Nota: poiché i nomi delle tabelle non sono univoci per database, per essere sicuri, è necessario qualificare lo schema per i nomi delle tabelle. Inoltre, limito la funzione allo schema predefinito "pubblico". Adattarsi alle proprie esigenze, ma assicurarsi di escludere gli schemi di sistema pg_*
e information_schema
.
Stai molto attento con queste funzioni. Nuotano il tuo database. Ho aggiunto un dispositivo di sicurezza per bambini. Commenta la RAISE NOTICE
linea e il commento EXECUTE
per adescare la 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()
richiede Postgres 9.1 o successivo. Nelle versioni precedenti concatenare la stringa di query in questo modo:
'TRUNCATE TABLE ' || quote_ident(_sch) || '.' || quote_ident(_tbl) || ' CASCADE';
Singolo comando, nessun loop
Dal momento che possiamo TRUNCATE
più tabelle contemporaneamente non abbiamo bisogno di alcun cursore o ciclo:
Aggrega tutti i nomi di tabella ed esegue una singola istruzione. Più semplice, più veloce:
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;
Chiamata:
SELECT truncate_tables('postgres');
Query raffinata
Non hai nemmeno bisogno di una funzione. In Postgres 9.0+ puoi eseguire comandi dinamici in DO
un'istruzione. E in Postgres 9.5+ la sintassi può essere ancora più semplice:
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$;
Circa la differenza tra pg_class
, pg_tables
e information_schema.tables
:
Informazioni sui regclass
nomi di tabella citati:
Per uso ripetuto
Crea un database "modello" (chiamiamolo my_template
) con la tua struttura vanilla e tutte le tabelle vuote. Quindi passare attraverso un DROP
/CREATE DATABASE
ciclo:
DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;
Questo è estremamente veloce , perché Postgres copia l'intera struttura a livello di file. Nessun problema di concorrenza o altri costi generali che ti rallentano.
Se connessioni simultanee ti impediscono di eliminare il DB, considera: