postgresql: INSERIR EM… (SELECIONE *…)

124

Não tenho certeza se o seu SQL padrão:

 INSERT INTO tblA 
 (SELECT id, time 
    FROM tblB 
   WHERE time > 1000)  

O que estou procurando é: e se tblA e tblB estiverem em diferentes servidores de banco de dados .

O PostgreSql fornece algum utilitário ou possui alguma funcionalidade que ajude a usar INSERT query with PGresult struct

Quero dizer, SELECT id, time FROM tblB ...vai voltar a PGresult*usar PQexec. É possível usar essa estrutura em outra PQexecpara executar um comando INSERT.

Edição:
Se não for possível, então eu iria para extrair os valores de PQresult * e criar uma sintaxe de instrução INSERT múltipla como:

INSERT INTO films (code, title, did, date_prod, kind) VALUES
    ('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
    ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy'); 

É possível criar uma declaração preparada com isso !! :(

Mayank
fonte
Não sei se a sintaxe INSERT que você postou é ANSI, mas é amplamente suportada (Oracle, MySQL, SQL Server, SQLite ...). Mas os suportes não são necessários.
OMG Ponies

Respostas:

151

Como Henrik escreveu, você pode usar o dblink para conectar o banco de dados remoto e buscar o resultado. Por exemplo:

psql dbtest
CREATE TABLE tblB (id serial, time integer);
INSERT INTO tblB (time) VALUES (5000), (2000);

psql postgres
CREATE TABLE tblA (id serial, time integer);

INSERT INTO tblA
    SELECT id, time 
    FROM dblink('dbname=dbtest', 'SELECT id, time FROM tblB')
    AS t(id integer, time integer)
    WHERE time > 1000;

TABLE tblA;
 id | time 
----+------
  1 | 5000
  2 | 2000
(2 rows)

O PostgreSQL possui pseudo-tipo de registro (apenas para argumento da função ou tipo de resultado), o que permite consultar dados de outra tabela (desconhecida).

Editar:

Você pode fazê-lo como declaração preparada, se quiser, e também funciona:

PREPARE migrate_data (integer) AS
INSERT INTO tblA
    SELECT id, time
    FROM dblink('dbname=dbtest', 'SELECT id, time FROM tblB')
    AS t(id integer, time integer)
    WHERE time > $1;

EXECUTE migrate_data(1000);
-- DEALLOCATE migrate_data;

Editar (sim, outro):

Acabei de ver sua pergunta revisada (fechada como duplicada ou muito parecida com isso).

Se meu entendimento estiver correto (o postgres possui tbla e dbtest tem tblb e você deseja inserir remotamente com seleção local , não selecionar remotamente com inserção local, como acima):

psql dbtest

SELECT dblink_exec
(
    'dbname=postgres',
    'INSERT INTO tbla
        SELECT id, time
        FROM dblink
        (
            ''dbname=dbtest'',
            ''SELECT id, time FROM tblb''
        )
        AS t(id integer, time integer)
        WHERE time > 1000;'
);

Eu não gosto desse dblink aninhado, mas AFAIK não posso me referir ao tblB no corpo dblink_exec . Use LIMIT para especificar as 20 principais linhas, mas acho que você precisa classificá-las usando a cláusula ORDER BY primeiro.

Grzegorz Szpetkowski
fonte
1
Obrigado pela sua resposta. Bem, mais uma pergunta rápida ... INSERT INTO tblA SELECT id, time FROM dblink('dbname=dbtest', 'SELECT id, time FROM tblB') AS t(id integer, time integer) WHERE time > 1000; Posso fazer uma declaração preparada com isso?
Mayank
Olá @ grzegorz-szpetkowski, Essa lógica está dando erro: ERRO: a senha é necessária DETALHE: Os não-usuários devem fornecer uma senha na cadeia de conexão.
Neel Darji
34

Se você deseja inserir na coluna especificar:

INSERT INTO table (time)
(SELECT time FROM 
    dblink('dbname=dbtest', 'SELECT time FROM tblB') AS t(time integer) 
    WHERE time > 1000
);
Piotr Olaszewski
fonte
9

Você pode usar o dblink para criar uma exibição resolvida em outro banco de dados. Esse banco de dados pode estar em outro servidor.

Hendrik Brummermann
fonte
Obrigado pela resposta. Mas eu não entendi como INSERT INTO ... (SELECT FROM ...)vai funcionar usando o dblink. O que eu preciso é INSERT INTO ...que seja executado na sessão dblink para outro DB Server, mas (SELECT FROM ...)na minha sessão atual.
Mayank
Você acabou de definir tblA como a visualização apoiada pelo dblink. Assim, inserções, atualizações e exclusões serão feitas no outro banco de dados. dblink não é somente leitura.
Hendrik Brummermann
9

Essa notação (vista aqui pela primeira vez ) também parece útil:

insert into postagem (
  resumopostagem,
  textopostagem,
  dtliberacaopostagem,
  idmediaimgpostagem,
  idcatolico,
  idminisermao,
  idtipopostagem
) select
  resumominisermao,
  textominisermao,
  diaminisermao,
  idmediaimgminisermao,
  idcatolico ,
  idminisermao,
  1
from
  minisermao    
Sombriks
fonte
2
Isso funciona apenas quando as tabelas estão no mesmo banco de dados. A pergunta é sobre a cópia de dados de uma tabela em um banco de dados diferente .
Nitin Nain #
2
insert into TABLENAMEA (A,B,C,D) 
select A::integer,B,C,D from TABLENAMEB
mahesh ingale
fonte
1

Aqui está uma solução alternativa, sem usar dblink.

Suponha que B represente o banco de dados de origem e A represente o banco de dados de destino:

  1. Copie a tabela do banco de dados de origem para o banco de dados de destino:

    pg_dump -t <source_table> <source_db> | psql <target_db>
  2. Abra o prompt do psql, conecte-se ao target_db e use um simples insert:

    psql
    # \c <target_db>;
    # INSERT INTO <target_table>(id, x, y) SELECT id, x, y FROM <source_table>;
  3. No final, exclua a cópia da tabela de origem que você criou na tabela de destino .

    # DROP TABLE <source_table>;
Nitin Nain
fonte