PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Postgres-Massen-INSERT-Funktion mit JSON-Argumenten

Für Tausende von Datensätzen

1. Erstellen Sie eine temporäre Tabelle mit Eingabezeilen, die aus Ihren Werten $1 besteht , $2 , $3 . Der schnellste Weg zum Hochladen ist COPY - oder den \copy meta-Befehl von psql wenn sich die Daten nicht auf derselben Maschine befinden. Nehmen wir diese Tabelle an:

CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);

Ich habe eine PK-Einschränkung hinzugefügt, die völlig optional ist, aber sicherstellt, dass wir es mit eindeutigen Nicht-Null-Int-Werten zu tun haben. Wenn Sie für Eingabedaten bürgen können, brauchen Sie die Einschränkung nicht.

2. Verketten Sie Ihre Befehle mit datenmodifizierenden CTEs. Wie wir unter Ihrer vorherigen Frage festgestellt haben , gibt es bei diesem speziellen Vorgang keine Rennbedingungen, um die man sich kümmern muss.

WITH ins1 AS (
   INSERT INTO table1 AS t1 (id, val1, val2)
   SELECT id, val1, val2 FROM tmp ON CONFLICT DO NOTHING
   RETURNING t1.id, t1.val1, t1.val2  -- only actually inserted rows returned
   )
, ins2 AS (
   INSERT INTO table2 (table1_id, val1)
   SELECT id, val1 FROM ins1
   )
UPDATE table3 t3
SET    val2 = i.val2
     , time = now()
FROM   ins1 i
WHERE  t3.table1_id = i.id;

Schritt 1. und 2. müssen in derselben Sitzung ausgeführt werden (nicht notwendigerweise dieselbe Transaktion), da der Gültigkeitsbereich temporärer Tabellen an dieselbe Sitzung gebunden ist.

Beachten Sie das UPDATE hängt nur vom 1. INSERT ab , Erfolg des 2. INSERT ist garantiert, da es kein ON CONFLICT DO NOTHING gibt und die gesamte Operation würde rückgängig gemacht, wenn es einen Konflikt im 2. INSERT gibt .

Verwandte:

Für nur ein paar Platten

Es gibt verschiedene Möglichkeiten, wie. Ihre Idee, ein JSON-Array an eine Funktion zu übergeben, ist eine davon. Wenn Objekte mit der Zieltabelle übereinstimmen, können Sie json_populate_recordset() in einem einzigen INSERT Anfrage. Oder verwenden Sie einfach den INSERT (als vorbereitete Anweisung) ohne Funktionswrapper.

INSERT INTO target_tbl  -- it's ok to omit target columns here
SELECT *
FROM   json_populate_recordset(null::target_tbl,  -- use same table type
          json '[{ "id": "1", "val1": "1-val1", "val2": "1-val2" },
                 { "id": "2", "val1": "2-val1", "val2": "2-val2" },
                 { "id": "3", "val1": "3-val1", "val2": "3-val2" },
                 { "id": "4", "val1": "4-val1", "val2": "4-val2" }]');

Für nur eine Handvoll Spalten können Sie auch ein Array für jede Spalte übergeben und diese parallel durchlaufen. Sie können dies mit einer einfachen Schleife auf dem Array-Index tun. Seit Postgres 9.4 gibt es auch das praktische unnest() mit mehreren Parametern, um alles in einer einzigen Abfrage zu erledigen:

Die beste Lösung hängt von Ihrem Datenformat ab .