191

I'm not sure if its standard SQL:

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

What I'm looking for is: what if tblA and tblB are in different DB Servers.

Does PostgreSql gives any utility or has any functionality that will help to use INSERT query with PGresult struct

I mean SELECT id, time FROM tblB ... will return a PGresult* on using PQexec. Is it possible to use this struct in another PQexec to execute an INSERT command.

EDIT:
If not possible then I would go for extracting the values from PQresult* and create a multiple INSERT statement syntax like:

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

Is it possible to create a prepared statement out of this!! :(

lospejos
  • 1,976
  • 3
  • 19
  • 35
Mayank
  • 5,454
  • 9
  • 37
  • 60
  • I don't know if the INSERT syntax you posted is ANSI, but it is widely supported (Oracle, MySQL, SQL Server, SQLite...). But the brackets aren't necessary. – OMG Ponies May 21 '11 at 16:57

8 Answers8

209

As Henrik wrote you can use dblink to connect remote database and fetch result. For example:

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 has record pseudo-type (only for function's argument or result type), which allows you query data from another (unknown) table.

Edit:

You can make it as prepared statement if you want and it works as well:

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;

Edit (yeah, another):

I just saw your revised question (closed as duplicate, or just very similar to this).

If my understanding is correct (postgres has tbla and dbtest has tblb and you want remote insert with local select, not remote select with local insert as above):

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

I don't like that nested dblink, but AFAIK I can't reference to tblB in dblink_exec body. Use LIMIT to specify top 20 rows, but I think you need to sort them using ORDER BY clause first.

Community
  • 1
  • 1
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • 1
    Thanks for your response. Well, one more quick question... `INSERT INTO tblA SELECT id, time FROM dblink('dbname=dbtest', 'SELECT id, time FROM tblB') AS t(id integer, time integer) WHERE time > 1000; ` Can I make a prepared statement out of this? – Mayank May 21 '11 at 19:28
  • Hi @grzegorz-szpetkowski, This logic is giving error : ERROR: password is required DETAIL: Non-superusers must provide a password in the connection string. – Neel Darji May 17 '20 at 06:25
  • What if you have a query with a lot of select statements and want to push the result into a table on another server? Is it possible to *push* the data, say, use dblink on the single "insert into" instead of on each and every select (i.e. *pull*), and execute the query on the "source" server instead of the "target"? – Hendrik Wiese May 26 '21 at 08:42
62

If you want insert into specify column:

INSERT INTO table (time)
(SELECT time FROM 
    dblink('dbname=dbtest', 'SELECT time FROM tblB') AS t(time integer) 
    WHERE time > 1000
);
Piotr Olaszewski
  • 6,017
  • 5
  • 38
  • 65
24

This notation (first seen here) looks useful too:

insert into postagem (
  resumopostagem,
  textopostagem,
  dtliberacaopostagem,
  idmediaimgpostagem,
  idcatolico,
  idminisermao,
  idtipopostagem
) select
  resumominisermao,
  textominisermao,
  diaminisermao,
  idmediaimgminisermao,
  idcatolico ,
  idminisermao,
  1
from
  minisermao    
Sombriks
  • 3,370
  • 4
  • 34
  • 54
  • 5
    This only works when the tables are in the same database. The Question is regarding copying data from a **table in a different database**. – Nitin Nain Sep 01 '18 at 03:19
10

You can use dblink to create a view that is resolved in another database. This database may be on another server.

Hendrik Brummermann
  • 8,242
  • 3
  • 31
  • 55
  • Thanks for the reply. But I did not get how `INSERT INTO ... (SELECT FROM ...)` will work using dblink. What I need is `INSERT INTO ...` to be run in dblink session to other DB Server, but `(SELECT FROM ...)` in my current session. – Mayank May 21 '11 at 17:32
  • You just define tblA as view that is backed by dblink. So inserts, updates, deletes will be done in the other database. dblink is not readonly. – Hendrik Brummermann May 21 '11 at 18:41
8
insert into TABLENAMEA (A,B,C,D) 
select A::integer,B,C,D from TABLENAMEB
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
mahesh ingale
  • 97
  • 1
  • 1
5

If you are looking for PERFORMANCE, give where condition inside the db link query. Otherwise it fetch all data from the foreign table and apply the where condition.

INSERT INTO tblA (id,time) 
SELECT id, time FROM  dblink('dbname=dbname port=5432 host=10.10.90.190 user=postgresuser password=pass123', 
'select id, time from tblB  where time>'''||1000||'''')
AS t1(id integer, time integer)  
REMITH
  • 1,049
  • 12
  • 12
2

I am going to SELECT Databasee_One(10.0.0.10) data from Database_Two (10.0.0.20)

Connect to 10.0.0.20 and create DBLink Extenstion:

CREATE EXTENSION dblink;

Test the connection for Database_One:

SELECT dblink_connect('host=10.0.0.10 user=postgres password=dummy dbname=DB_ONE');

Create foreign data wrapper and server for global authentication:

CREATE FOREIGN DATA WRAPPER postgres VALIDATOR postgresql_fdw_validator;

You can use this server object for cross database queries:

CREATE SERVER dbonepostgres FOREIGN DATA WRAPPER postgres OPTIONS (hostaddr '10.0.0.10', dbname 'DB_ONE');

Mapping of user and server:

CREATE USER MAPPING FOR postgres SERVER dbonepostgres OPTIONS (user 'postgres', password 'dummy');

Test dblink:

SELECT dblink_connect('dbonepostgres');

Import data from 10.0.0.10 into 10.0.0.20

INSERT INTO tableA   
  SELECT 
    column1,
    ,column2, 
    ...
  FROM dblink('dbonepostgres', 'SELECT column1, column2, ... from public.tableA')
  AS data(column1 DATATYPE, column2 DATATYPE, ...)
;
-1

Here's an alternate solution, without using dblink.

Suppose B represents the source database and A represents the target database: Then,

  1. Copy table from source DB to target DB:

    pg_dump -t <source_table> <source_db> | psql <target_db>
    
  2. Open psql prompt, connect to target_db, and use a simple insert:

    psql
    # \c <target_db>;
    # INSERT INTO <target_table>(id, x, y) SELECT id, x, y FROM <source_table>;
    
  3. At the end, delete the copy of source_table that you created in target_table.

    # DROP TABLE <source_table>;
    
Nitin Nain
  • 5,113
  • 1
  • 37
  • 51