postgresql: INSERT INTO… (SELECT *…)

125

No estoy seguro de si es SQL estándar:

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

Lo que estoy buscando es: ¿qué pasa si tblA y tblB están en diferentes servidores DB ?

¿PostgreSql ofrece alguna utilidad o tiene alguna funcionalidad que ayude a usar? INSERT query with PGresult struct

Quiero decir SELECT id, time FROM tblB ..., volveré PGresult*a usar PQexec. ¿Es posible usar esta estructura en otra PQexecpara ejecutar un comando INSERT?

EDITAR:
Si no es posible, iría a extraer los valores de PQresult * y crearía una sintaxis de declaración INSERT múltiple 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'); 

¿Es posible crear una declaración preparada a partir de esto? :(

Mayank
fuente
No sé si la sintaxis INSERT que publicó es ANSI, pero es ampliamente compatible (Oracle, MySQL, SQL Server, SQLite ...). Pero los corchetes no son necesarios.
OMG Ponies

Respuestas:

152

Como escribió Henrik, puede usar dblink para conectar la base de datos remota y obtener el resultado. Por ejemplo:

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)

PostgreSQL tiene un pseudo-tipo de registro (solo para el argumento de la función o el tipo de resultado), que le permite consultar datos de otra tabla (desconocida).

Editar:

Puede hacerlo como una declaración preparada si lo desea y también 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 (sí, otro):

Acabo de ver su pregunta revisada (cerrada como duplicada o simplemente muy similar a esta).

Si mi entendimiento es correcto (postgres tiene tbla y dbtest tiene tblb y desea una inserción remota con selección local , no selección remota con inserción local como arriba):

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;'
);

No me gusta ese dblink anidado, pero AFAIK, no puedo hacer referencia a tblB en el cuerpo dblink_exec . Use LIMIT para especificar las 20 filas superiores, pero creo que primero debe ordenarlas usando la cláusula ORDER BY.

Grzegorz Szpetkowski
fuente
1
Gracias por su respuesta. Bueno, una pregunta rápida más ... INSERT INTO tblA SELECT id, time FROM dblink('dbname=dbtest', 'SELECT id, time FROM tblB') AS t(id integer, time integer) WHERE time > 1000; ¿Puedo hacer una declaración preparada sobre esto?
Mayank
Hola @ grzegorz-szpetkowski, Esta lógica está dando error: ERROR: se requiere contraseña DETALLE: Los no superusuarios deben proporcionar una contraseña en la cadena de conexión.
Neel Darji
34

Si desea insertar en la columna especificada:

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

Puede utilizar dblink para crear una vista que se resuelve en otra base de datos. Esta base de datos puede estar en otro servidor.

Hendrik Brummermann
fuente
Gracias por la respuesta. Pero no entendí cómo INSERT INTO ... (SELECT FROM ...)funcionará el uso de dblink. Lo que necesito es INSERT INTO ...ejecutar una sesión dblink en otro servidor DB, pero (SELECT FROM ...)en mi sesión actual.
Mayank
Simplemente define tblA como vista respaldada por dblink. Entonces, las inserciones, actualizaciones y eliminaciones se realizarán en la otra base de datos. dblink no es de solo lectura.
Hendrik Brummermann
9

Esta notación (vista por primera vez aquí ) también parece útil:

insert into postagem (
  resumopostagem,
  textopostagem,
  dtliberacaopostagem,
  idmediaimgpostagem,
  idcatolico,
  idminisermao,
  idtipopostagem
) select
  resumominisermao,
  textominisermao,
  diaminisermao,
  idmediaimgminisermao,
  idcatolico ,
  idminisermao,
  1
from
  minisermao    
Sombriks
fuente
2
Esto solo funciona cuando las tablas están en la misma base de datos. La pregunta se refiere a copiar datos de una tabla en una base de datos diferente .
Nitin Nain
2
insert into TABLENAMEA (A,B,C,D) 
select A::integer,B,C,D from TABLENAMEB
mahesh ingale
fuente
1

Aquí hay una solución alternativa, sin usar dblink .

Suponga que B representa la base de datos de origen y A representa la base de datos de destino: Entonces,

  1. Copie la tabla de la base de datos de origen a la base de datos de destino:

    pg_dump -t <source_table> <source_db> | psql <target_db>
  2. Abra el indicador psql, conéctese a target_db y use un simple insert:

    psql
    # \c <target_db>;
    # INSERT INTO <target_table>(id, x, y) SELECT id, x, y FROM <source_table>;
  3. Al final, elimine la copia de source_table que creó en target_table .

    # DROP TABLE <source_table>;
Nitin Nain
fuente