postgresql: INSERT IN… (SELECT *…)

124

Ich bin nicht sicher, ob es Standard-SQL ist:

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

Was ich suche ist: was ist, wenn TBLA und TBLB sind in verschiedenen DB - Server .

Gibt PostgreSql ein Dienstprogramm an oder verfügt es über Funktionen, die bei der Verwendung hilfreich sind? INSERT query with PGresult struct

Ich meine, ich SELECT id, time FROM tblB ...werde ein PGresult*bei Verwendung zurückgeben PQexec. Ist es möglich, diese Struktur in einer anderen PQexeczu verwenden, um einen INSERT-Befehl auszuführen?

BEARBEITEN:
Wenn dies nicht möglich ist, würde ich die Werte aus PQresult * extrahieren und eine Syntax für mehrere INSERT-Anweisungen erstellen, wie:

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

Ist es möglich, daraus eine vorbereitete Aussage zu machen !! :((

Mayank
quelle
Ich weiß nicht, ob die von Ihnen veröffentlichte INSERT-Syntax ANSI ist, sie wird jedoch weitgehend unterstützt (Oracle, MySQL, SQL Server, SQLite ...). Die Klammern sind jedoch nicht erforderlich.
OMG Ponys

Antworten:

151

Wie Henrik schrieb, können Sie dblink verwenden, um eine entfernte Datenbank zu verbinden und das Ergebnis abzurufen. Beispielsweise:

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 verfügt über einen Datensatzpseudotyp (nur für das Argument oder den Ergebnistyp der Funktion), mit dem Sie Daten aus einer anderen (unbekannten) Tabelle abfragen können.

Bearbeiten:

Sie können es als vorbereitete Aussage machen, wenn Sie wollen und es funktioniert auch:

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;

Bearbeiten (ja, noch eine):

Ich habe gerade Ihre überarbeitete Frage gesehen (als Duplikat geschlossen oder nur sehr ähnlich).

Wenn mein Verständnis korrekt ist (postgres hat tbla und dbtest hat tblb und Sie möchten eine Remote-Einfügung mit lokaler Auswahl , keine Remote-Auswahl mit lokaler Einfügung wie oben):

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

Ich mag diesen verschachtelten Dblink nicht, aber AFAIK Ich kann nicht auf tblB im dblink_exec- Body verweisen . Verwenden Sie LIMIT, um die obersten 20 Zeilen anzugeben, aber ich denke, Sie müssen sie zuerst mit der ORDER BY-Klausel sortieren.

Grzegorz Szpetkowski
quelle
1
Vielen Dank für Ihre Antwort. Nun noch eine kurze Frage ... INSERT INTO tblA SELECT id, time FROM dblink('dbname=dbtest', 'SELECT id, time FROM tblB') AS t(id integer, time integer) WHERE time > 1000; Kann ich daraus eine vorbereitete Aussage machen?
Mayank
Hi @ grzegorz-szpetkowski, Diese Logik gibt einen Fehler aus: FEHLER: Passwort ist erforderlich DETAIL: Nicht-Superuser müssen ein Passwort in der Verbindungszeichenfolge angeben.
Neel Darji
34

Wenn Sie in die angegebene Spalte einfügen möchten:

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

Mit dblink können Sie eine Ansicht erstellen, die in einer anderen Datenbank aufgelöst wird. Diese Datenbank befindet sich möglicherweise auf einem anderen Server.

Hendrik Brummermann
quelle
Danke für die Antwort. Aber ich habe nicht verstanden, wie INSERT INTO ... (SELECT FROM ...)es mit dblink funktionieren wird. Ich muss INSERT INTO ...in einer dblink-Sitzung mit einem anderen DB-Server ausgeführt werden, jedoch (SELECT FROM ...)in meiner aktuellen Sitzung.
Mayank
Sie definieren tblA einfach als Ansicht, die von dblink unterstützt wird. Das Einfügen, Aktualisieren und Löschen erfolgt also in der anderen Datenbank. dblink ist nicht schreibgeschützt.
Hendrik Brummermann
9

Diese Notation (zuerst gesehen hier ) sieht auch nützlich:

insert into postagem (
  resumopostagem,
  textopostagem,
  dtliberacaopostagem,
  idmediaimgpostagem,
  idcatolico,
  idminisermao,
  idtipopostagem
) select
  resumominisermao,
  textominisermao,
  diaminisermao,
  idmediaimgminisermao,
  idcatolico ,
  idminisermao,
  1
from
  minisermao    
Sombriks
quelle
2
Dies funktioniert nur, wenn sich die Tabellen in derselben Datenbank befinden. Die Frage bezieht sich auf das Kopieren von Daten aus einer Tabelle in eine andere Datenbank .
Nitin Nain
2
insert into TABLENAMEA (A,B,C,D) 
select A::integer,B,C,D from TABLENAMEB
Mahesh Ingale
quelle
1

Hier ist eine alternative Lösung ohne Verwendung dblink.

Angenommen, B repräsentiert die Quellendatenbank und A repräsentiert die Zieldatenbank: Dann

  1. Tabelle von Quell-DB in Ziel-DB kopieren:

    pg_dump -t <source_table> <source_db> | psql <target_db>
  2. Öffnen Sie die psql-Eingabeaufforderung, stellen Sie eine Verbindung zu target_db her und verwenden Sie eine einfache Funktion insert:

    psql
    # \c <target_db>;
    # INSERT INTO <target_table>(id, x, y) SELECT id, x, y FROM <source_table>;
  3. Löschen Sie am Ende die Kopie von source_table , die Sie in target_table erstellt haben .

    # DROP TABLE <source_table>;
Nitin Nain
quelle