postgresql: INSERT INTO… (SELECT *…)


125

Я не уверен, что его стандартный SQL:

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

Я ищу: что, если tblA и tblB находятся на разных серверах БД .

Предоставляет ли 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 Ponies

Ответы:


153

Как писал Хенрик, вы можете использовать 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, и вам нужна удаленная вставка с локальным выбором , а не удаленный выбор с локальной вставкой, как указано выше):

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, я не могу ссылаться на tblB в теле dblink_exec . Используйте 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, эта логика дает ошибку: ОШИБКА: требуется пароль. ДЕТАЛИ: Не суперпользователи должны указать пароль в строке подключения.
— Нил Дарджи

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
Это работает только тогда, когда таблицы находятся в одной базе данных. Вопрос касается копирования данных из таблицы в другую базу данных .
— Нитин Наин


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. В конце удалите копию source_table, которую вы создали в target_table .

    # DROP TABLE <source_table>;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.