PostgreSQL:INSERT INTO…(SELECT *…)


124

我不确定它的标准SQL:

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

我要寻找的是:如果tblA和tblB在不同的DB Server中会怎样

PostgreSql是否提供任何实用程序或任何功能来帮助使用 INSERT query with PGresult struct

我的意思是SELECT id, time FROM tblB ...将返回PGresult*使用PQexec。是否可以在另一个结构中使用此结构PQexec来执行INSERT命令。

编辑:
如果不可能的话,那么我将从PQresult *中提取值,并创建多个INSERT语句语法,例如:

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

是否可以据此创建准备好的语句!!:(


我不知道您发布的INSERT语法是否为ANSI,但是得到了广泛支持(Oracle,MySQL,SQL Server,SQLite ...)。但是括号不是必需的。
OMG小马

Answers:


151

正如Henrik所写,您可以使用dblink连接远程数据库并获取结果。例如:

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具有记录伪类型(仅用于函数的参数或结果类型),它允许您从另一个(未知)表中查询数据。

编辑:

您可以根据需要将其作为准备好的语句,它也可以正常工作:

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;

编辑(是的,另一个):

我刚刚看到您修改过的问题(重复出现,或者与此非常相似)。

如果我的理解是正确的(postgres具有tbla且dbtest具有tblb,并且您希望使用local select进行远程插入,而不是使用本地插入进行远程选择,则如上所述):

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

我不喜欢嵌套的dblink,但是AFAIK我无法在dblink_exec主体中引用tblB。使用LIMIT指定前20行,但我认为您需要首先使用ORDER BY子句对它们进行排序。


1
感谢您的答复。好吧,还有一个快速的问题... INSERT INTO tblA SELECT id, time FROM dblink('dbname=dbtest', 'SELECT id, time FROM tblB') AS t(id integer, time integer) WHERE time > 1000; 我可以据此作一个准备好的陈述吗?
Mayank

@ grzegorz-szpetkowski,您好:此逻辑给出了错误信息:错误:需要密码详细信息:非超级用户必须在连接字符串中提供密码。
Neel Darji

34

如果要插入指定列:

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

9

您可以使用dblink创建在另一个数据库中解析的视图。该数据库可能在另一台服务器上。


谢谢回复。但是我不知道如何INSERT INTO ... (SELECT FROM ...)使用dblink进行工作。我需要INSERT INTO ...在与其他数据库服务器的dblink会话中运行,但要(SELECT FROM ...)在当前会话中运行。
Mayank

您只需将tblA定义为由dblink支持的视图。因此,插入,更新,删除将在另一个数据库中完成。dblink不是只读的。
亨德里克·布鲁默曼

9

这种表示法(在这里首次看到)看起来也很有用:

insert into postagem (
  resumopostagem,
  textopostagem,
  dtliberacaopostagem,
  idmediaimgpostagem,
  idcatolico,
  idminisermao,
  idtipopostagem
) select
  resumominisermao,
  textominisermao,
  diaminisermao,
  idmediaimgminisermao,
  idcatolico ,
  idminisermao,
  1
from
  minisermao    

2
仅当表位于同一数据库中时,此方法才有效。问题是关于从另一个数据库中复制数据。
Nitin Nain '18


1

这是替代解决方案,无需使用 dblink

假设B代表源数据库,而A代表目标数据库:然后,

  1. 将表从源数据库复制到目标数据库:

    pg_dump -t <source_table> <source_db> | psql <target_db>
  2. 打开psql提示符,连接到target_db,并使用一个简单的命令insert

    psql
    # \c <target_db>;
    # INSERT INTO <target_table>(id, x, y) SELECT id, x, y FROM <source_table>;
  3. 最后,删除您在target_table中创建的source_table的副本。

    # DROP TABLE <source_table>;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.