Utilice CTE de modificación de datos :
WITH ins1 AS (
INSERT INTO sample(firstname, lastname)
VALUES ('fai55', 'shaggk')
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 uno INSERT
depende del anterior. SELECT
en lugar de, VALUES
se asegura de que no se inserte nada en las tablas subsidiarias si no se devuelve ninguna fila de una anterior INSERT
. (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
('fai55', 'shaggk', 'ss', 'ss2')
, ('fai56', 'XXaggk', 'xx', 'xx2')
)
, ins1 AS (
INSERT INTO sample (firstname, lastname)
SELECT firstname, lastname
FROM data
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 tipos explícitas en una VALUES
expresión independiente , a diferencia de una VALUES
expresión adjunta a una INSERT
donde los tipos de datos se derivan de la tabla de destino. Ver:
Si varias filas pueden tener idénticas (firstname, lastname)
, es posible que deba doblar duplicados para la primera INSERT
:
...
INSERT INTO sample (firstname, lastname)
SELECT DISTINCT firstname, lastname FROM data
...
Puede utilizar una tabla (temporal) como fuente de datos en lugar del CTE data
.
Probablemente tendría sentido combinar esto con una restricción ÚNICA (firstname, lastname)
en la tabla y una ON CONFLICT
cláusula en la consulta.
Relacionado:
INSERT INTO sample1 (user_id, adddetails)
, ¿no debería serlo(sample_id, addetails)
?Algo como esto
with first_insert as ( insert into sample(firstname,lastname) values('fai55','shaggk') RETURNING id ), second_insert as ( insert into sample1( id ,adddetails) values ( (select id from first_insert), 'ss') RETURNING user_id ) insert into sample2 ( id ,adddetails) values ( (select user_id from first_insert), 'ss');
Como
sample2
no se necesita la identificación generada del inserto en , eliminé lareturning
cláusula del último inserto.fuente
Normalmente, usaría una transacción para evitar escribir consultas complicadas.
http://www.postgresql.org/docs/current/static/sql-begin.html
http://dev.mysql.com/doc/refman/5.7/en/commit.html
También puede usar un CTE, asumiendo que su etiqueta de Postgres es correcta. Por ejemplo:
with sample_ids as ( insert into sample(firstname, lastname) values('fai55','shaggk') RETURNING id ), sample1_ids as ( insert into sample1(id, adddetails) select id,'ss' from sample_ids RETURNING id, user_id ) insert into sample2(id, user_id, value) select id, user_id, 'val' from sample1_ids RETURNING id, user_id;
fuente
Puede crear un desencadenador de inserción posterior en la tabla Sample para insertarlo en las otras dos tablas.
El único problema que veo al hacer esto es que no tendrá una forma de insertar detalles adicionales, siempre estará vacío o, en este caso, ss. No hay forma de insertar una columna en una muestra que no esté actualmente en la tabla de muestras, por lo que no puede enviarla junto con la inserción inicial.
Otra opción sería crear un procedimiento almacenado para ejecutar sus inserciones.
Tiene la pregunta taged mysql y postgressql ¿de qué base de datos estamos hablando aquí?
fuente