Exclua todos os dados no banco de dados Postgres

14

Criei um db db novo a partir de um servidor de produção com os sinalizadores --data-onlye --column-inserts, portanto, só tenho um monte de instruções de inserção para inserir dados ao executar uma restauração em um servidor intermediário.

pg_dump -h localhost -U adminuser --data-only --column-inserts maindb > maindb.sql

Como excluo todos os dados no banco de dados do servidor intermediário primeiro, antes de restaurar os dados do dump de produção?

Eu quero excluir todos os dados apenas para não precisar soltar e criar o banco de dados e todas essas coisas. Eu só quero remover dados e inserir novos dados, isso é tudo.

Não tenho a opção de descartar e criar o banco de dados por vários motivos. Vou ter que remover todos os dados e apenas inserir apenas, portanto, o que for preciso para descobrir como fazer isso, estou disposto a fazê-lo, mas preciso de ajuda, obviamente, para começar.

Eu também preciso automatizar esse processo. Automatizará "descarregando dados do banco de dados de produção", "excluindo dados no banco de dados intermediário" e "restaurando dados no banco de dados intermediário". Eu só preciso de ajuda na parte "excluindo dados no banco de dados temporário".

Estou executando no PostgreSQL 9.5.2

uberrebu
fonte

Respostas:

24

Você não precisa descartar o banco de dados; deve ser o suficiente para descartar todos os objetos no banco de dados. Isso pode ser feito usando

drop owned by adminuser

Se você criar o dump SQL, incluindo as create tableinstruções (portanto, sem a --data-onlyopção), tudo ficará bem.

Você também pode remover o --column-insertsentão, o que tornará a importação muito mais rápida.


No entanto, se você deseja excluir tudo, pode fazer isso com um pouco de SQL dinâmico:

do
$$
declare
  l_stmt text;
begin
  select 'truncate ' || string_agg(format('%I.%I', schemaname, tablename), ',')
    into l_stmt
  from pg_tables
  where schemaname in ('public');

  execute l_stmt;
end;
$$

Isso truncará todas as tabelas no esquema publiccom uma única instrução que também funcionará mesmo se houver muitas restrições de chave estrangeira conectando todas as tabelas. Se suas tabelas estiverem espalhadas por vários esquemas, você precisará adicioná-las na wherecondição

um cavalo sem nome
fonte
Entendo ... ele faz a mesma coisa que o @ypercube mencionado acima para usar este comando TRUNCATE table1, table2, ... <list of all tables>;? ambos fazem a mesma coisa?
Uberrebu
11
@babababa: Sim, minha resposta simplesmente gera e executa essa declaração dinamicamente, para que você não precise digitar todos os nomes de tabelas e, se adicionar uma nova tabela, ela será automaticamente incluída.
precisa saber é o seguinte
bom apenas tentei e ele funciona, @ypercube se trabalha muito ... muito obrigado
uberrebu
6

O pg_restore possui um sinalizador --clean (ou possivelmente --create) que excluirá automaticamente os dados antes de executar as operações.

A excelente documentação deve ajudá-lo muito ...

Apenas para esclarecer, caso seja confuso:

Limpe (descarte) os objetos do banco de dados antes de recriá-los. (A menos que - se exista for usado, isso poderá gerar algumas mensagens de erro inofensivas, se algum objeto não estiver presente no banco de dados de destino.)

Isso não descartará o banco de dados real .. apenas as tabelas / visualizações / etc.

Se, por algum motivo, descartar e recriar as tabelas não for aceitável, você precisará trabalhar mais para criar manualmente um script que crie um data onlydump a partir do banco de dados de origem, problemas TRUNCATEou DELETEno banco de dados de destino e, em seguida, carrega o despejo de dados. Não há nenhuma maneira rápida / inteligente de fazer isso, até onde eu saiba.

Joishi Bodio
fonte
O sinalizador --clean APAGARÁ APENAS os dados e manterá as estruturas de banco de dados e tabelas iguais mas vazias?
Uberrebu
Ele emitirá uma tabela descartada antes de uma tabela de criação. Quaisquer tabelas que existem no arquivo de despejo. Eu ESPERARIA que o arquivo de despejo contenha as informações para recriar a tabela exatamente como existia antes (incluindo FKeys, etc.). Mas isso realmente depende de como você criou o arquivo de despejo. No entanto, como você continua mencionando "armazenamento temporário", parece que o que você está realmente procurando é uma maneira de preencher tabelas de armazenamento temporário em um data warehouse com dados de um banco de dados de produção. Se esse é o seu objetivo, um arquivo de despejo é provavelmente a abordagem errada ..
Joishi Bodio
não é isso que pretendo fazer, eu só quero excluir dados ... a estrutura de banco de dados e tabelas permanecerá a mesma e intocada ... minha pergunta é bem clara sobre o que eu quero fazer, mesmo a partir do título
uberrebu
Então, lamento dizer, sua solução será muito mais difícil.
Joishi Bodio
3
SELECT 'TRUNCATE ' || input_table_name || ' CASCADE;' AS truncate_query FROM(SELECT table_schema || '.' || table_name AS input_table_name FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema') AND table_schema NOT LIKE 'pg_toast%') AS information;  

A consulta acima irá gerar consultas truncadas para todas as tabelas no banco de dados.

Thirumal
fonte
0

Nota: minha resposta é sobre realmente excluir as tabelas e outros objetos de banco de dados; para apagar todos os dados em tabelas, ou seja truncar todas as tabelas , Endre Ambos forneceu uma declaração similarily bem executado (execução direta), um mês depois.

Para os casos em que você não pode simplesmente DROP SCHEMA public CASCADE;, DROP OWNED BY current_user;ou algo assim, aqui está um script SQL independente que eu escrevi, que é seguro para transações (ou seja, você pode colocá-lo entre BEGIN;e ROLLBACK;apenas para testá-lo ou COMMIT;realmente fazer a ação) e limpa “todos” os objetos do banco de dados ... bem, todos aqueles usados ​​no banco de dados que nosso aplicativo usa ou eu poderia acrescentar sensatamente, que é:

  • gatilhos nas tabelas
  • restrições de tabela (FK, PK, CHECK, UNIQUE)
  • indicações
  • VIEWs (normal ou materializado)
  • mesas
  • sequências
  • rotinas (funções agregadas, funções, procedimentos)
  • todos os esquemas não padrão (por exemplo, não publicou internos ao banco de dados) "nós" possuímos: o script é útil quando executado como "não um superusuário de banco de dados"; um superusuário pode eliminar todos os esquemas (os realmente importantes ainda são explicitamente excluídos)
  • extensões (contribuídas pelo usuário, mas normalmente as deixo deliberadamente)

Não são descartados (alguns deliberados; outros apenas porque eu não tinha exemplo em nosso banco de dados):

  • o publicesquema (por exemplo, para itens fornecidos por extensão)
  • colações e outras coisas de localidade
  • gatilhos de evento
  • pesquisa de texto,… (veja aqui outras coisas que eu poderia ter perdido)
  • funções ou outras configurações de segurança
  • tipos compostos
  • mesas de brinde
  • FDW e tabelas estrangeiras

Isso é realmente útil para os casos em que o dump que você deseja restaurar é de uma versão de esquema de banco de dados diferente (por exemplo, com Debian dbconfig-common, Flyway ou Liquibase / DB-Manul) do que o banco de dados no qual você deseja restaurá-lo.

Também tenho uma versão que exclui "tudo, exceto duas tabelas e o que lhes pertence" (uma sequência, testada manualmente, desculpe, eu sei, chata), caso alguém esteja interessado; o diff é pequeno. Entre em contato comigo ou consulte este repositório, se estiver interessado.

SQL

-- Copyright © 2019, 2020
--      mirabilos <[email protected]>
--
-- Provided that these terms and disclaimer and all copyright notices
-- are retained or reproduced in an accompanying document, permission
-- is granted to deal in this work without restriction, including un‐
-- limited rights to use, publicly perform, distribute, sell, modify,
-- merge, give away, or sublicence.
--
-- This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
-- the utmost extent permitted by applicable law, neither express nor
-- implied; without malicious intent or gross negligence. In no event
-- may a licensor, author or contributor be held liable for indirect,
-- direct, other damage, loss, or other issues arising in any way out
-- of dealing in the work, even if advised of the possibility of such
-- damage or existence of a defect, except proven that it results out
-- of said person’s immediate fault when using the work as intended.
-- -
-- Drop everything from the PostgreSQL database.

DO $$
DECLARE
        q TEXT;
        r RECORD;
BEGIN
        -- triggers
        FOR r IN (SELECT pns.nspname, pc.relname, pt.tgname
                FROM pg_catalog.pg_trigger pt, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pt.tgrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pt.tgisinternal=false
            ) LOOP
                EXECUTE format('DROP TRIGGER %I ON %I.%I;',
                    r.tgname, r.nspname, r.relname);
        END LOOP;
        -- constraints #1: foreign key
        FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
                FROM pg_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pcon.contype='f'
            ) LOOP
                EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
                    r.nspname, r.relname, r.conname);
        END LOOP;
        -- constraints #2: the rest
        FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
                FROM pg_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pcon.contype<>'f'
            ) LOOP
                EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
                    r.nspname, r.relname, r.conname);
        END LOOP;
        -- indicēs
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='i'
            ) LOOP
                EXECUTE format('DROP INDEX %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- normal and materialised views
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind IN ('v', 'm')
            ) LOOP
                EXECUTE format('DROP VIEW %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- tables
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='r'
            ) LOOP
                EXECUTE format('DROP TABLE %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- sequences
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='S'
            ) LOOP
                EXECUTE format('DROP SEQUENCE %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- extensions (only if necessary; keep them normally)
        FOR r IN (SELECT pns.nspname, pe.extname
                FROM pg_catalog.pg_extension pe, pg_catalog.pg_namespace pns
                WHERE pns.oid=pe.extnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
            ) LOOP
                EXECUTE format('DROP EXTENSION %I;', r.extname);
        END LOOP;
        -- aggregate functions first (because they depend on other functions)
        FOR r IN (SELECT pns.nspname, pp.proname, pp.oid
                FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns, pg_catalog.pg_aggregate pagg
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pagg.aggfnoid=pp.oid
            ) LOOP
                EXECUTE format('DROP AGGREGATE %I.%I(%s);',
                    r.nspname, r.proname,
                    pg_get_function_identity_arguments(r.oid));
        END LOOP;
        -- routines (functions, aggregate functions, procedures, window functions)
        IF EXISTS (SELECT * FROM pg_catalog.pg_attribute
                WHERE attrelid='pg_catalog.pg_proc'::regclass
                    AND attname='prokind' -- PostgreSQL 11+
            ) THEN
                q := 'CASE pp.prokind
                        WHEN ''p'' THEN ''PROCEDURE''
                        WHEN ''a'' THEN ''AGGREGATE''
                        ELSE ''FUNCTION''
                    END';
        ELSIF EXISTS (SELECT * FROM pg_catalog.pg_attribute
                WHERE attrelid='pg_catalog.pg_proc'::regclass
                    AND attname='proisagg' -- PostgreSQL ≤10
            ) THEN
                q := 'CASE pp.proisagg
                        WHEN true THEN ''AGGREGATE''
                        ELSE ''FUNCTION''
                    END';
        ELSE
                q := '''FUNCTION''';
        END IF;
        FOR r IN EXECUTE 'SELECT pns.nspname, pp.proname, pp.oid, ' || q || ' AS pt
                FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN (''information_schema'', ''pg_catalog'', ''pg_toast'')
            ' LOOP
                EXECUTE format('DROP %s %I.%I(%s);', r.pt,
                    r.nspname, r.proname,
                    pg_get_function_identity_arguments(r.oid));
        END LOOP;
        -- nōn-default schemata we own; assume to be run by a not-superuser
        FOR r IN (SELECT pns.nspname
                FROM pg_catalog.pg_namespace pns, pg_catalog.pg_roles pr
                WHERE pr.oid=pns.nspowner
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast', 'public')
                    AND pr.rolname=current_user
            ) LOOP
                EXECUTE format('DROP SCHEMA %I;', r.nspname);
        END LOOP;
        -- voilà
        RAISE NOTICE 'Database cleared!';
END; $$;

Testado, exceto adições posteriores ( extensionscontribuído por Clément Prévost ), no PostgreSQL 9.6 ( jessie-backports). Remoção agregada testada em 9.6 e 12.2, remoção de procedimento testada em 12.2 também. Correções de bugs e melhorias adicionais são bem-vindas!

mirabilos
fonte
Perfeito, aqui está o meu código para as extensões, ele deve ser colocado antes das funções / procedimentos: - extensões FOR r IN (SELECT pns.nspname, pe.extname FROM pg_extension pe, pg_namespace pns WHERE pns.oid = pe.extnamespace AND pns .nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')) Formato LOOP EXECUTE ('DROP EXTENSION% I;', r.extname); END LOOP;
Clément Prévost
@ ClémentPrévost obrigado, mesclei seu comentário no código (espero que tenha feito certo, os comentários não têm formatação, por favor, revise). No entanto, normalmente deixo as extensões sem exclusão deliberada (meu caso de uso é restaurado a partir de backups com versões de esquema diferentes e normalmente tenho exatamente uma extensão, PL / pgSQL, carregada). Pode ser útil para alguns, então, obrigado!
mirabilos 14/07/19
Perfeito, obrigado :)
Clément Prévost