Exportar linhas específicas de uma tabela do PostgreSQL como script INSERT SQL


196

Eu tenho um esquema de banco de dados chamado: nyummye uma tabela chamada cimory:

create table nyummy.cimory (
  id numeric(10,0) not null,
  name character varying(60) not null,
  city character varying(50) not null,
  CONSTRAINT cimory_pkey PRIMARY KEY (id)
);

Quero exportar os cimorydados da tabela como inserir arquivo de script SQL. No entanto, eu só quero exportar registros / dados onde a cidade é igual a 'tokyo' (suponha que os dados da cidade sejam todos minúsculos).

Como fazer isso?

Não importa se a solução está em ferramentas GUI de freeware ou em linha de comando (embora a solução de ferramentas GUI seja melhor). Eu tentei o pgAdmin III, mas não consigo encontrar uma opção para fazer isso.


2
você pode pular as instruções INSERT e apenas copiar usando SELECT diretamente entre os bancos de dados. albertech.blogspot.com/2016/11/...
jar

O PostgreSQL não pode selecionar entre os bancos de dados. Pelo menos, as versões mais antigas não podem e nem o Greenplum, não conhecem o 9.x.
21416 PhilHibbs

Sei que isso é antigo, mas eu só queria mencionar que é possível selecionar entre bancos de dados usando o dblink , que está disponível desde pelo menos a v8.3. Ele usa servidores e invólucros de dados externos para conectar-se a bancos de dados "remotos". Isso funciona se esses bancos de dados existem na mesma instância ou em hosts completamente diferentes. Eu o usei bastante extensivamente para criar visualizações materializadas em outros bancos de dados para facilitar determinados relatórios e tal e funciona muito bem.
G_Hosa_Phat 5/03

Respostas:


281

Crie uma tabela com o conjunto que você deseja exportar e, em seguida, use o utilitário de linha de comando pg_dump para exportar para um arquivo:

create table export_table as 
select id, name, city
from nyummy.cimory
where city = 'tokyo'
$ pg_dump --table=export_table --data-only --column-inserts my_database > data.sql

--column-inserts irá despejar como comandos de inserção com nomes de colunas.

--data-only não despeje o esquema.

Conforme comentado abaixo, a criação de uma exibição em vez de uma tabela evitará a criação da tabela sempre que uma nova exportação for necessária.


3
Tudo bem, até agora sua solução funciona. Uma coisa que falta é que eu preciso adicionar "-U user_name". Eu também quase obtive sucesso com a ferramenta ToraSQL, mas há erros nos dados de data e hora no resultado do script. Se ninguém pode dar GUI solução ferramenta em 2 dias, a sua resposta será aceito
nula

2
Apenas deseja compartilhar com outras pessoas, você também pode usar esta ferramenta gráfica gratuita: SQL Workbench / J (com o driver postgreSQL jdbc4), para fazer a mesma coisa.
Nulo

1
Isso seria muito melhor create view export_view..., pois a visualização permaneceria atualizada com as alterações na tabela base. Os documentos dizem --table=table: Dump only tables (or **views**...que eu tinha alguma esperança de que isso funcionasse, mas despejar uma exibição infelizmente não gera dados. : P
poshest

@poshest Funciona para mim na versão 9.5. O que exatamente você tentou?
Clodoaldo Neto

@ClodoaldoNeto oh, OK great! Espero também poder fazê-lo funcionar. Eu usei a pg_dump --table=my_schema.my_view --data-only --inserts my_db > data.sqlversão 9.5.3 e minha createdeclaração era a mesma que a sua, exceto create view.... Tudo o que recebo na saída são os comentários e SETdeclarações habituais do pg_dump . Não tenho certeza de onde estou errado.
poshest

176

Para um uso de exportação apenas de dadosCOPY .
Você obtém um arquivo com uma linha da tabela por linha como texto sem formatação (não INSERTcomandos), é menor e mais rápido:

COPY (SELECT * FROM nyummy.cimory WHERE city = 'tokio') TO '/path/to/file.csv';

Importe o mesmo para outra tabela da mesma estrutura em qualquer lugar com:

COPY other_tbl FROM '/path/to/file.csv';

COPYescreve e lê arquivos locais para o servidor , ao contrário de programas clientes como pg_dumpou psqlo que ler e escrever arquivos local para o cliente . Se os dois rodam na mesma máquina, não importa muito, mas é para conexões remotas.

Há também o \copycomando do psql que:

Executa uma cópia de front-end (cliente). Essa é uma operação que executa um COPYcomando SQL , mas, em vez de o servidor ler ou gravar o arquivo especificado, o psql lê ou grava o arquivo e roteia os dados entre o servidor e o sistema de arquivos local. Isso significa que a acessibilidade e os privilégios de arquivo são do usuário local, não do servidor, e não são necessários privilégios de superusuário SQL.


10
O OP solicita especificamente dados como inserção de arquivo de script sql . Eu acho que ele está falando sobre insertcomandos, não é?
Clodoaldo Neto 10/10

1
@Clodoaldo: Você pode estar certo; nesse caso, sua resposta seria mais adequada. Também se pode copiar o script CREATE no pgAdmin separadamente (como o OP menciona GUIs).
Erwin Brandstetter

3
STDINe STDOUTpode ser usado no lugar do caminho do arquivo, útil para pequenas exportações de dados.
Amir Ali Akbari

1
Sem o --column-insertssinalizador, pg_dump usa um COPYde STDIN para cada uma das tabelas no código SQL gerado.
Randall

2
Verifique se a ordem das colunas que você seleciona corresponde à ordem das colunas no banco de dados de destino. Caso contrário, isso pode falhar, ou pior, ser bem-sucedido, mas insira dados incorretos.
18138 Nathan Wallace

32

Esta é uma maneira fácil e rápida de exportar uma tabela para um script com o pgAdmin manualmente sem instalações extras :

  1. Clique com o botão direito na tabela de destino e selecione "Backup".
  2. Selecione um caminho de arquivo para armazenar o backup. Como Formato, escolha "Simples".
  3. Abra a guia "Opções de despejo nº 2" na parte inferior e marque "Usar inserções de coluna".
  4. Clique no botão Backup.
  5. Se você abrir o arquivo resultante com um leitor de texto (por exemplo, o bloco de notas ++), receberá um script para criar a tabela inteira. A partir daí, você pode simplesmente copiar as INSERT-Statements geradas.

Esse método também funciona com a técnica de criar uma tabela export_ conforme demonstrado na resposta de @Clodoaldo Neto.

Clique à direita na tabela de destino e escolha "Backup"

Escolha um caminho de destino e altere o formato para "Simples"

Abra a guia "Opções de despejo nº 2" na parte inferior e marque "Usar inserções de coluna"

Você pode copiar as instruções INSERT de lá.


Quando faço isso, não há opção "Bakckup". Este é o pgAdmin III v1.18.1, conectado ao Greenplum 4.3.4.1 (baseado no PostgreSQL 8.2.15).
PhilHibbs

Eu instalei pgAdmin III v1.18.1 e não foi a opção "backup". Eu me conectei a um PostgreSQL 9.5. Portanto, o problema provavelmente está entre o pgAdmin e o Greenplum.
And R:

Funciona como pretendido no pgAdmin4
Nikhil

9

O SQL Workbench possui esse recurso.

Após executar uma consulta, clique com o botão direito do mouse nos resultados da consulta e escolha "Copiar dados como SQL> Inserir SQL"


1
Isso funciona muito bem. Ao escolher 'postgres' como o 'driver', é provável que você precise fazer o download dos drivers JDBC: jdbc.postgresql.org/download.html (é um arquivo .jar - java binário) e adicione-o como 'driver' da conexão postgresql. A seqüência de conexão (ou URL como na interface) deve se parecer com isso: jdbc: postgresql: //127.0.0.1: 5432 / nome_bd
mrmuggles

O DBVisualizer possui um recurso semelhante e excelente que pode copiar para um arquivo ou diretamente para a área de transferência.
Noumenon

8

Para o meu caso de uso, eu era capaz de simplesmente canalizar para grep.

pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql

2
É preciso considerar ter 'Tóquio' em outro campo.
Buyut Joko Rivai

@BuyutJokoRivai já que é uma tabela somente despejar na maioria dos casos ele deve estar bem
Ismail Iqbal

Maneira mais inteligente entre os outros sobre o caso <3
Nam G VU

Embora com tabela grande, você irá despejar todas as linhas para o grep, que é o caso das armadilhas da sua solução. Em seguida, a consulta maneira que nós e armazena o resultado em uma tabela para despejar como aqui stackoverflow.com/a/12816187/248616 é mais suiteable
Nam G VU

5

Tentei escrever um procedimento para isso, com base nos códigos @PhilHibbs, de uma maneira diferente. Por favor, dê uma olhada e teste.

 CREATE OR REPLACE FUNCTION dump(IN p_schema text, IN p_table text, IN p_where text)
   RETURNS setof text AS
 $BODY$
 DECLARE
     dumpquery_0 text;
     dumpquery_1 text;
     selquery text;
     selvalue text;
     valrec record;
     colrec record;
 BEGIN

     -- ------ --
     -- GLOBAL --
     --   build base INSERT
     --   build SELECT array[ ... ]
     dumpquery_0 := 'INSERT INTO ' ||  quote_ident(p_schema) || '.' || quote_ident(p_table) || '(';
     selquery    := 'SELECT array[';

     <<label0>>
     FOR colrec IN SELECT table_schema, table_name, column_name, data_type
                   FROM information_schema.columns
                   WHERE table_name = p_table and table_schema = p_schema
                   ORDER BY ordinal_position
     LOOP
         dumpquery_0 := dumpquery_0 || quote_ident(colrec.column_name) || ',';
         selquery    := selquery    || 'CAST(' || quote_ident(colrec.column_name) || ' AS TEXT),';
     END LOOP label0;

     dumpquery_0 := substring(dumpquery_0 ,1,length(dumpquery_0)-1) || ')';
     dumpquery_0 := dumpquery_0 || ' VALUES (';
     selquery    := substring(selquery    ,1,length(selquery)-1)    || '] AS MYARRAY';
     selquery    := selquery    || ' FROM ' ||quote_ident(p_schema)||'.'||quote_ident(p_table);
     selquery    := selquery    || ' WHERE '||p_where;
     -- GLOBAL --
     -- ------ --

     -- ----------- --
     -- SELECT LOOP --
     --   execute SELECT built and loop on each row
     <<label1>>
     FOR valrec IN  EXECUTE  selquery
     LOOP
         dumpquery_1 := '';
         IF not found THEN
             EXIT ;
         END IF;

         -- ----------- --
         -- LOOP ARRAY (EACH FIELDS) --
         <<label2>>
         FOREACH selvalue in ARRAY valrec.MYARRAY
         LOOP
             IF selvalue IS NULL
             THEN selvalue := 'NULL';
             ELSE selvalue := quote_literal(selvalue);
             END IF;
             dumpquery_1 := dumpquery_1 || selvalue || ',';
         END LOOP label2;
         dumpquery_1 := substring(dumpquery_1 ,1,length(dumpquery_1)-1) || ');';
         -- LOOP ARRAY (EACH FIELD) --
         -- ----------- --

         -- debug: RETURN NEXT dumpquery_0 || dumpquery_1 || ' --' || selquery;
         -- debug: RETURN NEXT selquery;
         RETURN NEXT dumpquery_0 || dumpquery_1;

     END LOOP label1 ;
     -- SELECT LOOP --
     -- ----------- --

 RETURN ;
 END
 $BODY$
   LANGUAGE plpgsql VOLATILE;

E depois :

-- for a range
SELECT dump('public', 'my_table','my_id between 123456 and 123459'); 
-- for the entire table
SELECT dump('public', 'my_table','true');

testado no meu postgres 9.1, com uma tabela com tipo de dados de campo misto (texto, double, int, timestamp sem fuso horário, etc.).

É por isso que o CAST no tipo TEXT é necessário. Meu teste foi executado corretamente por cerca de 9 milhões de linhas, parece que falhou pouco antes dos 18 minutos de execução.

ps: Encontrei um equivalente para mysql na WEB.


3

Você pode visualizar a tabela com registros específicos e depois despejar o arquivo sql

CREATE VIEW foo AS
SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'

3
Eu tentei no pgAdmin III, mas para o objeto View, não há opção para dumping.
Nulo

Tente navicat. Eu estou usando-o e tem opção de script de exportação sql
Giorgi Peikrishvili

@ Giorgi: existe a versão freeware?
null,

Não é possível usar o Postgres 9.1
HCarrasko 02/02

2

Acabei de iniciar um procedimento rápido para fazer isso. Funciona apenas para uma única linha, portanto, crio uma exibição temporária que apenas seleciona a linha desejada e substituo o pg_temp.temp_view pela tabela real na qual desejo inserir.

CREATE OR REPLACE FUNCTION dv_util.gen_insert_statement(IN p_schema text, IN p_table text)
  RETURNS text AS
$BODY$
DECLARE
    selquery text; 
    valquery text; 
    selvalue text; 
    colvalue text; 
    colrec record;
BEGIN

    selquery := 'INSERT INTO ' ||  quote_ident(p_schema) || '.' || quote_ident(p_table);

    selquery := selquery || '(';

    valquery := ' VALUES (';
    FOR colrec IN SELECT table_schema, table_name, column_name, data_type
                  FROM information_schema.columns 
                  WHERE table_name = p_table and table_schema = p_schema 
                  ORDER BY ordinal_position 
    LOOP
      selquery := selquery || quote_ident(colrec.column_name) || ',';

      selvalue := 
        'SELECT CASE WHEN ' || quote_ident(colrec.column_name) || ' IS NULL' || 
                   ' THEN ''NULL''' || 
                   ' ELSE '''' || quote_literal('|| quote_ident(colrec.column_name) || ')::text || ''''' || 
                   ' END' || 
        ' FROM '||quote_ident(p_schema)||'.'||quote_ident(p_table);
      EXECUTE selvalue INTO colvalue;
      valquery := valquery || colvalue || ',';
    END LOOP;
    -- Replace the last , with a )
    selquery := substring(selquery,1,length(selquery)-1) || ')';
    valquery := substring(valquery,1,length(valquery)-1) || ')';

    selquery := selquery || valquery;

RETURN selquery;
END
$BODY$
  LANGUAGE plpgsql VOLATILE;

Invocado assim:

SELECT distinct dv_util.gen_insert_statement('pg_temp_' || sess_id::text,'my_data') 
from pg_stat_activity 
where procpid = pg_backend_pid()

Não testei isso contra ataques de injeção. Informe-me se a chamada quote_literal não for suficiente para isso.

Também funciona apenas para colunas que podem ser simplesmente convertidas em :: text e retornadas novamente.

Também é para o Greenplum, mas não consigo pensar em uma razão pela qual ele não funcionaria no Postgres, CMIIW.


-2

você tentou no pgadmin executando a consulta com " EXECUTE QUERY WRITE RESULT TO FILE " opção

é apenas exportar os dados, caso contrário tente

pg_dump -t view_name DB_name > db.sql

-t opção usada para ==> Despejar apenas tabelas (ou visualizações ou sequências) tabela correspondente, consulte


1
Isso exportará apenas uma create viewinstrução
cdmckay
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.