Усечение всех таблиц в базе данных Postgres

Мне регулярно нужно удалять все данные из моей базы данных PostgreSQL перед перестройкой. Как мне сделать это прямо в SQL?

На данный момент мне удалось придумать оператор SQL, который возвращает все команды, которые мне нужно выполнить:

SELECT 'TRUNCATE TABLE ' ||  tablename || ';' FROM pg_tables WHERE tableowner='MYUSER';

Но я не вижу способа выполнить их программно, если они у меня есть.


person Sig    schedule 13.05.2010    source источник


Ответы (11)


FrustratedWithFormsDesigner верен, PL / pgSQL может это сделать. Вот сценарий:

CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$
DECLARE
    statements CURSOR FOR
        SELECT tablename FROM pg_tables
        WHERE tableowner = username AND schemaname = 'public';
BEGIN
    FOR stmt IN statements LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Это создает сохраненную функцию (вам нужно сделать это только один раз), которую вы впоследствии можете использовать следующим образом:

SELECT truncate_tables('MYUSER');
person Henning    schedule 13.05.2010
comment
Пришлось немного переделать, но после этого все заработало как шарм! Я никогда раньше не использовал plpgsql, так что это заняло бы у меня много времени. Спасибо! Для тех, кому это нужно, я добавил код, который в итоге использовал, в конце этого поста. - person Sig; 14.05.2010
comment
Извините, я, вероятно, думал в Oracle PL / SQL :( Я исправил синтаксическую ошибку в своем коде выше. - person Henning; 14.05.2010
comment
вы также можете переместить оператор SELECT непосредственно в цикл FOR. DECLARE r RECORD; затем для цикла: FOR r IN SELECT tablename FROM pg_tables LOOP - person Michael Buen; 14.05.2010
comment
Я бы добавил КАСКАД в ТАБЛИЦУ ОБРЕЗКИ - person Bogdan Gusiev; 20.05.2010
comment
Фактически, для усечения ВСЕХ таблиц требуется условие CASCADE! - person Hobbes; 02.08.2011
comment
Просто помните, что вам нужно перезапустить свои последовательности (автоматическое приращение), иначе ваши новые данные начнутся с предыдущего максимального номера идентификатора ... - person rizidoro; 25.03.2015
comment
@Henning Я понимаю, что это старый вопрос, но будет ли добавление RESTART IDENTITY хорошим дополнением к запросу? - person Berry M.; 16.10.2017
comment
МОЙ БОГ!! Я только что усек все свои таблицы в общедоступной схеме .... пожалуйста, добавьте еще один параметр схемы, чтобы функция усекала таблицы только в предоставленной схеме! - person roneo; 01.12.2017
comment
@roneo см. вопрос: ALL TABLES в базе данных! - person Magno C; 15.03.2019
comment
Я могу подтвердить, что все работает нормально. - person Arefe; 06.01.2021

Явные курсоры редко нужны в 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  
      -- dangerous, test before you execute!
      RAISE NOTICE '%',  -- once confident, comment this line ...
      -- EXECUTE         -- ... and uncomment this one
         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
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
  (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
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
   (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 копирует всю структуру на уровне файлов. Никаких проблем с параллелизмом или других накладных расходов, замедляющих вас.

Если одновременные подключения не позволяют вам отбросить БД, примите во внимание:

person Erwin Brandstetter    schedule 22.08.2012
comment
Стоит отметить, что эта последняя функция стерла ВСЕ базы данных. Не только тот, который в настоящее время подключен ... да ... назовите меня наивным, но это действительно не было ясно из этого сообщения. - person Amalgovinus; 10.09.2015
comment
@Amalgovinus: Какая последняя функция? Ни одна из функций в моем ответе не касается чего-либо за пределами текущей базы данных (кроме DROP DATABASE mydb, очевидно). Может быть, вы путаете схемы с базами данных? - person Erwin Brandstetter; 10.09.2015
comment
Самый последний с DO $ func $. Я использовал одно и то же имя схемы в двух разных базах данных, поэтому похоже, что мои данные были удалены из обеих. так что да, я перепутал этих двоих - person Amalgovinus; 10.09.2015
comment
@Amalgovinus: Нет, это невозможно. Команда DO (как и любой другой оператор SQL) выполняется в текущей базе данных исключительно. У Postgres нет возможности получить доступ к другим базам данных в той же транзакции. Для этого вам нужно будет использовать dblink или FDW. Но это действительно влияет на все схемы в текущей базе данных - если вы не добавите WHERE t.schemaname = 'public', чтобы ограничить эффект одной конкретной схемы в этом конкретном случае. - person Erwin Brandstetter; 10.09.2015
comment
Действительно приятно знать об этих шаблонах. Это может быть полезно даже в сценариях автоматического тестирования, где может потребоваться сброс / подготовка базы данных. - person hbobenicio; 16.03.2017
comment
Я исправил ваш уточненный запрос, у него была своенравная лишняя точка с запятой, которой подавлялись мои postgres. ERROR: mismatched parentheses at or near ";" LINE 8: ... AND relnamespace = 'public'::regnamespace; - person Tim Abell; 02.08.2018
comment
Спасибо за отличный ответ, я использую одиночную команду, без цикла, который возвращает команду TRUNCATE, как мне ее выполнить? - person Mahyar; 06.11.2018
comment
@Mahyar меня это тоже сначала смутило, прокомментируйте строку RAISE и раскомментируйте строку EXECUTE. - person Tshirtman; 07.10.2019
comment
Почему в вашем Refined query примере EXECUTE закомментировано? Кажется, я не могу заставить этот метод работать. Без EXECUTE он просто создает строку из команды TRUNCATE TABLE ..., но не запускает ее. Если раскомментировать EXECUTE, получится syntax error at or near "SELECT". В итоге мне пришлось удалить строку RAISE NOTICE и раскомментировать EXECUTE, чтобы запустить ее. - person CodingWithSpike; 17.04.2020
comment
@CodingWithSpike: Возможно, вы пропустили заметку вверху: Be very careful with these functions. They nuke your database. I added a child safety device. Comment the RAISE NOTICE line and uncomment EXECUTE to prime the bomb ... - person Erwin Brandstetter; 20.08.2020

Если мне нужно это сделать, я просто создам схему sql текущей базы данных, затем отброшу и создаю базу данных, а затем загрузю базу данных со схемой sql.

Ниже приведены необходимые шаги:

1) Создать дамп схемы базы данных (--schema-only)

pg_dump mydb -s > schema.sql

2) Отбросить базу данных

drop database mydb;

3) Создать базу данных

create database mydb;

4) Импортировать схему

psql mydb < schema.sql

person Sandip Ransing    schedule 05.08.2014

В этом случае, вероятно, было бы лучше просто иметь пустую базу данных, которую вы используете в качестве шаблона, и, когда вам нужно обновить, удалите существующую базу данных и создайте новую из шаблона.

person Scott Bailey    schedule 13.05.2010

Просто выполните запрос ниже:

DO $$ DECLARE
    r RECORD;
BEGIN
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || '';
    END LOOP;
END $$;
person Cong Nguyen    schedule 03.08.2020
comment
Я пробовал много других решений, но работает только это. - person miko866; 13.05.2021

Ребята, лучший и чистый способ:

1) Создать дамп схемы базы данных (--schema-only) pg_dump mydb -s> schema.sql

2) Отбросить базу данных Удалить базу данных mydb;

3) Создать базу данных создать базу данных mydb;

4) Импортировать схему psql mydb ‹schema.sql

Это работает для меня!

Хорошего дня. Хирам Уокер

person Hiram Walker    schedule 05.06.2018

Могли бы вы использовать динамический SQL для выполнения каждого оператора по очереди? Для этого вам, вероятно, придется написать сценарий PL / pgSQL.

http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html (раздел 38.5.4. Выполнение динамических команд)

person FrustratedWithFormsDesigner    schedule 13.05.2010

Очистка AUTO_INCREMENT версия:

CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$
DECLARE
    statements CURSOR FOR
        SELECT tablename FROM pg_tables
        WHERE tableowner = username AND schemaname = 'public';
BEGIN
    FOR stmt IN statements LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';

        IF EXISTS (
            SELECT column_name 
            FROM information_schema.columns 
            WHERE table_name=quote_ident(stmt.tablename) and column_name='id'
        ) THEN
           EXECUTE 'ALTER SEQUENCE ' || quote_ident(stmt.tablename) || '_id_seq RESTART WITH 1';
        END IF;

    END LOOP;
END;
$$ LANGUAGE plpgsql;
person RomanGorbatko    schedule 17.08.2017

Вы также можете сделать это с помощью bash:

#!/bin/bash
PGPASSWORD='' psql -h 127.0.0.1 -Upostgres sng --tuples-only --command "SELECT 'TRUNCATE TABLE ' || schemaname || '.' ||  tablename || ';' FROM pg_tables WHERE schemaname in ('cms_test', 'ids_test', 'logs_test', 'sps_test');" | 
tr "\\n" " " | 
xargs -I{} psql -h 127.0.0.1 -Upostgres sng --command "{}"

Вам нужно будет настроить имена схем, пароли и имена пользователей в соответствии с вашими схемами.

person simao    schedule 09.04.2013

Если вы можете использовать psql, вы можете использовать \gexec мета-команду для выполнения запроса выход;

SELECT
    format('TRUNCATE TABLE %I.%I', ns.nspname, c.relname)
  FROM pg_namespace ns 
  JOIN pg_class c ON ns.oid = c.relnamespace
  JOIN pg_roles r ON r.oid = c.relowner
  WHERE
    ns.nspname = 'table schema' AND                               -- add table schema criteria 
    r.rolname = 'table owner' AND                                 -- add table owner criteria
    ns.nspname NOT IN ('pg_catalog', 'information_schema') AND    -- exclude system schemas
    c.relkind = 'r' AND                                           -- tables only
    has_table_privilege(c.oid, 'TRUNCATE')                        -- check current user has truncate privilege
  \gexec 

Обратите внимание, что \gexec введен в версию 9.6.

person Sahap Asci    schedule 17.03.2020

Для удаления данных и сохранения структур таблиц в pgAdmin вы можете:

  • Щелкните правой кнопкой мыши по базе данных -> резервное копирование, выберите «Только схема».
  • Отбросить базу данных
  • Создайте новую базу данных и назовите ее как прежнюю
  • Щелкните правой кнопкой мыши новую базу данных -> восстановить -> выберите резервную копию, выберите «Только схема»
person mYnDstrEAm    schedule 29.03.2017