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?