PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Postgres funzione INSERT di massa utilizzando argomenti JSON

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 .