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

Insérer des données dans 3 tables à la fois en utilisant Postgres

Utiliser des CTE modificateurs de données :

WITH ins1 AS (
   INSERT INTO sample(firstname, lastname)
   VALUES ('fai55', 'shaggk')
-- ON     CONFLICT DO NOTHING         -- optional addition in Postgres 9.5+
   RETURNING id AS sample_id
   )
, ins2 AS (
   INSERT INTO sample1 (sample_id, adddetails)
   SELECT sample_id, 'ss' FROM ins1
   RETURNING user_id
   )
INSERT INTO sample2 (user_id, value)
SELECT user_id, 'ss2' FROM ins2;

Chaque INSERT dépend de celui d'avant. SELECT au lieu de VALUES s'assure que rien n'est inséré dans les tables subsidiaires si aucune ligne n'est renvoyée d'un INSERT précédent . (Depuis Postgres 9.5+, vous pouvez ajouter un ON CONFLICT .)
C'est aussi un peu plus court et plus rapide de cette façon.

Généralement, il est plus pratique de fournir des lignes de données complètes au même endroit :

WITH data(firstname, lastname, adddetails, value) AS (
   VALUES                              -- provide data here
      ('fai55', 'shaggk', 'ss', 'ss2') -- see below
    , ('fai56', 'XXaggk', 'xx', 'xx2') -- works for multiple input rows
       --  more?                      
   )
, ins1 AS (
   INSERT INTO sample (firstname, lastname)
   SELECT firstname, lastname          -- DISTINCT? see below
   FROM   data
   -- ON     CONFLICT DO NOTHING       -- UNIQUE constraint? see below
   RETURNING firstname, lastname, id AS sample_id
   )
, ins2 AS (
   INSERT INTO sample1 (sample_id, adddetails)
   SELECT ins1.sample_id, d.adddetails
   FROM   data d
   JOIN   ins1 USING (firstname, lastname)
   RETURNING sample_id, user_id
   )
INSERT INTO sample2 (user_id, value)
SELECT ins2.user_id, d.value
FROM   data d
JOIN   ins1 USING (firstname, lastname)
JOIN   ins2 USING (sample_id);

db<>jouez ici

Vous aurez peut-être besoin de conversions de type explicites dans un VALUES autonome expression - par opposition à un VALUES expression attachée à un INSERT où les types de données sont dérivés de la table cible. Voir :

  • Diffusion du type NULL lors de la mise à jour de plusieurs lignes

Si plusieurs lignes peuvent contenir un (firstname, lastname) identique , vous devrez peut-être plier les doublons pour le premier INSERT :

...
INSERT INTO sample (firstname, lastname)
SELECT DISTINCT firstname, lastname FROM data
...

Vous pouvez utiliser une table (temporaire) comme source de données au lieu des data CTE .

Il serait probablement judicieux de combiner cela avec une contrainte UNIQUE sur (firstname, lastname) dans le tableau et un ON CONFLICT clause dans la requête.

Connexe :

  • Comment utiliser RETURNING avec ON CONFLICT dans PostgreSQL ?
  • SELECT ou INSERT est-il dans une fonction sujette à des conditions de concurrence ?