PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Fonction INSERT en bloc Postgres utilisant des arguments JSON

Pour des milliers d'enregistrements

1. Créez une table temporaire de lignes d'entrée, composée de vos valeurs $1 , $2 , $3 . Le moyen le plus rapide de télécharger est COPY - ou le \copy méta-commande de psql si les données ne sont pas sur la même machine. Supposons ce tableau :

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

J'ai ajouté une contrainte PK, qui est totalement facultative, mais elle garantit que nous avons affaire à des valeurs int uniques non nulles. Si vous pouvez vous porter garant des données d'entrée, vous n'avez pas besoin de la contrainte.

2. Enchaînez vos commandes avec des CTE modificateurs de données. Comme nous l'avons déterminé dans votre question précédente , il n'y a pas de conditions de course à prendre en compte dans cette opération particulière.

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;

Les étapes 1 et 2 doivent être exécutées dans la même session (pas nécessairement la même transaction), puisque la portée des tables temporaires est liée à la même session.

Remarque, la UPDATE ne dépend que du 1er INSERT , succès du 2ème INSERT est garanti, puisqu'il n'y a pas de ON CONFLICT DO NOTHING et toute l'opération serait annulée s'il y avait un conflit dans le 2ème INSERT .

Connexe :

Pour seulement quelques enregistrements

Il existe différentes options comment. Votre idée de passer un tableau JSON à une fonction en fait partie. Si les objets correspondent à la table cible, vous pouvez utiliser json_populate_recordset() en un seul INSERT requête. Ou utilisez simplement le INSERT (en tant qu'instruction préparée) sans wrapper de fonction.

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" }]');

Pour seulement quelques colonnes, vous pouvez également passer un tableau pour chaque colonne et les parcourir en parallèle. Vous pouvez le faire avec une simple boucle sur l'index du tableau. Depuis Postgres 9.4, il existe également le pratique unnest() avec plusieurs paramètres pour tout faire en une seule requête :

La meilleure solution dépend du format de données que vous avez .