sql >> Base de Datos >  >> RDS >> PostgreSQL

Inserte datos en 3 tablas a la vez usando Postgres

Usar CTE de modificación de datos :

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;

Cada INSERT depende del anterior. SELECT en lugar de VALUES se asegura de que no se inserte nada en las tablas auxiliares si no se devuelve ninguna fila de un INSERT anterior . (Desde Postgres 9.5+, puede agregar un ON CONFLICT .)
También es un poco más corto y rápido de esta manera.

Por lo general, es más conveniente proporcionar filas de datos completas en un solo lugar :

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<>violín aquí

Es posible que necesite conversiones de tipo explícitas en un VALUES independiente expresión - a diferencia de un VALUES expresión adjunta a un INSERT donde los tipos de datos se derivan de la tabla de destino. Ver:

  • Conversión de tipo NULL al actualizar varias filas

Si varias filas pueden venir con (firstname, lastname) idénticos , es posible que deba doblar duplicados para el primer INSERT :

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

Podría usar una tabla (temporal) como fuente de datos en lugar de los data de CTE .

Probablemente tendría sentido combinar esto con una restricción ÚNICA en (firstname, lastname) en la tabla y un ON CONFLICT cláusula en la consulta.

Relacionado:

  • ¿Cómo usar RETURNING con ON CONFLICT en PostgreSQL?
  • ¿Es SELECCIONAR o INSERTAR en una función propensa a condiciones de carrera?