Per migliaia di record
1. Crea una tabella temporanea di righe di input, composta dai tuoi valori $1
, $2
, $3
. Il modo più veloce per caricare è COPY
- o il \copy
metacomando di psql
se i dati non sono sulla stessa macchina. Supponiamo questa tabella:
CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);
Ho aggiunto un vincolo PK, che è totalmente facoltativo, ma assicura che abbiamo a che fare con valori int non nulli univoci. Se puoi garantire i dati di input, non hai bisogno del vincolo.
2. Concatena i tuoi comandi con CTE di modifica dei dati. Come abbiamo stabilito nella tua domanda precedente , non ci sono race condition di cui occuparsi in questa particolare operazione.
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;
I passaggi 1. e 2. devono essere eseguiti nella stessa sessione (non necessariamente la stessa transazione), poiché l'ambito delle tabelle temporanee è legato alla stessa sessione.
Nota, il UPDATE
dipende solo dal 1° INSERT
, successo del 2° INSERT
è garantito, poiché non esiste ON CONFLICT DO NOTHING
e l'intera operazione verrebbe annullata in caso di conflitto nel 2° INSERT
.
Correlati:
Solo per un paio di record
Ci sono varie opzioni come. La tua idea di passare un array JSON a una funzione è una di queste. Se gli oggetti corrispondono alla tabella di destinazione, puoi utilizzare json_populate_recordset()
in un unico INSERT
interrogazione. Oppure usa semplicemente il INSERT
(come istruzione preparata) senza wrapper di funzioni.
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" }]');
Per solo una manciata di colonne potresti anche passare un array per ciascuna colonna e scorrerle in parallelo. Puoi farlo con un semplice ciclo sull'indice dell'array. Da Postgres 9.4 c'è anche il comodo unnest()
con più parametri per fare tutto in un'unica query:
La soluzione migliore dipende dal formato dei dati che hai .