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.